私は、賃貸物件への mvc アプリケーションの開発者です。
モデルイモベル(不動産)
namespace Imobiliario.Models
{
[Table("Imoveis")]
public class Imovel
{
[Key]
public int ImovelID { get; set; }
[DisplayName("Tipo Cômodo")]
[Required(ErrorMessage = "Campo obrigatório.")]
public int TipoComodoID { get; set; }
public virtual TipoComodo TipoComodo { get; set; }
[DisplayName("Endereço")]
[Required(ErrorMessage = "Campo obrigatório.")]
public int EnderecoID { get; set; }
public virtual Endereco Endereco { get; set; }
[DisplayName("Quantidade de cômodos")]
[Required(ErrorMessage = "Campo obrigatório.")]
public int QtdComodos { get; set; }
[DisplayName("Quantidade de banheiros")]
[Required(ErrorMessage = "Campo obrigatório.")]
public int QtdBanheiros { get; set; }
[DisplayName("Alugado")]
public bool Alugado { get; set; }
[DisplayName("Valor do aluguel")]
[Required(ErrorMessage = "Campo obrigatório.")]
public decimal ValorAluguel { get; set; }
public virtual ICollection<DetalhesImovel> DetalhesImovel { get; set; }
public virtual ICollection<Imagem> Imagens { get; set; }
public virtual ICollection<Taxa> TaxasList { get; set; }
[ConcurrencyCheck]
[Timestamp]
public Byte[] Timestamp { get; set; }
}
}
モデル エンデレソ (住所):
namespace Imobiliario.Models
{
[Table("Enderecos")]
public class Endereco
{
[Key]
[ScaffoldColumn(false)]
public int EnderecoID { get; set; }
[DisplayName("Logradouro")]
[Required(ErrorMessage = "Campo obrigatório.")]
public string Logradouro { get; set; }
[DisplayName("Número")]
[Required(ErrorMessage = "Campo obrigatório.")]
public int Numero { get; set; }
[DisplayName("Complemento")]
public string Complemento { get; set; }
[DisplayName("Bairro")]
[Required(ErrorMessage = "Campo obrigatório.")]
public string Bairro { get; set; }
[DisplayName("Cidade")]
[Required(ErrorMessage = "Campo obrigatório.")]
public string Cidade { get; set; }
[DisplayName("Cep")]
[Required(ErrorMessage = "Campo obrigatório.")]
public string Cep { get; set; }
[DisplayName("Estado")]
[Required(ErrorMessage = "Campo obrigatório.")]
public string Estado { get; set; }
}
}
モデルDetalhesImovel(詳細):
namespace Imobiliario.Models
{
[Table("DetalhesImovel")]
public class DetalhesImovel
{
[Key]
public int DetalhesImovelID { get; set; }
[DisplayName("Descrição")]
public string Descricao { get; set; }
public string Grupo { get; set; }
[ScaffoldColumn(false)]
public DateTime DataCadastro { get; set; }
public virtual ICollection<Imovel> Imovel { get; set; }
public override bool Equals(object obj)
{
var param = (DetalhesImovel)obj;
if (DetalhesImovelID == param.DetalhesImovelID || Descricao == param.Descricao)
return true;
return false;
}
}
}
Imovelコントローラー:
namespace Imobiliario.Controllers
{
public class ImoveisController : Controller
{
private ImobiliarioDbContext db = new ImobiliarioDbContext();
//
// GET: /Imoveis/
public ActionResult Index(int? id, int? detalhesImovel, int? imagensImovel)
{
var viewModel = new IndexImovel();
viewModel.Imovel =
db.Imoveis.Include(i => i.DetalhesImovel.Select(d => d.Imovel))
.Include(i => i.TaxasList.Select(im => im.Imovel))
.Include(i => i.Imagens.Select(im => im.Imoveis))
.Include(i => i.TipoComodo)
.Include(i => i.Endereco)
.OrderBy(i => i.ImovelID);
return View(viewModel);
}
//
// GET: /Imoveis/Details/5
public ActionResult Details(int id = 0)
{
var imoveis = db.Imoveis.Include(i => i.DetalhesImovel.Select(d => d.Imovel))
.Include(i => i.TaxasList.Select(im => im.Imovel))
.Include(i => i.Imagens.Select(im => im.Imoveis))
.Include(i => i.TipoComodo)
.Include(i => i.Endereco)
.Where(i => i.ImovelID == id)
.OrderBy(i => i.ImovelID);
return View(imoveis.ToList());
}
//
// GET: /Imoveis/Create
public ActionResult Create()
{
ViewBag.TipoComodoID = new SelectList(db.TipoComodo, "TipoComodoID", "Descricao");
var todosDetalhes = db.DetalhesImoveis;
var viewModel = new List<ImovelDetalhes>();
foreach (var detalhe in todosDetalhes)
{
viewModel.Add(new ImovelDetalhes
{
Descricao = detalhe.Descricao,
DetalhesImovelID = detalhe.DetalhesImovelID,
});
}
ViewBag.Detalhes = viewModel;
return View();
}
//
// POST: /Imoveis/Create
[HttpPost]
public ActionResult Create(CreateImovel imo, string[] detalhesSelecionados, int tipoComodoID)
{
if (ModelState.IsValid)
{
imo.Imovel.TipoComodoID = tipoComodoID;
db.Enderecos.Add(imo.Endereco);
db.Imoveis.Add(imo.Imovel);
foreach (var item in db.DetalhesImoveis)
{
if (detalhesSelecionados.Contains(item.DetalhesImovelID.ToString()))
{
imo.Imovel.DetalhesImovel = new Collection<DetalhesImovel>();
imo.Imovel.DetalhesImovel.Add(item);
}
}
db.SaveChanges();
return RedirectToAction("Index");
}
return View(imo);
}
//
// GET: /Imoveis/Edit/5
public ActionResult Edit(int id = 0)
{
Imovel imovel =
db.Imoveis.Include(i => i.DetalhesImovel).Include(i => i.Endereco).Include(i => i.TipoComodo).Include(i => i.TaxasList).Single(
i => i.ImovelID == id);
PopularSeletorDetalhes(imovel);
PopularDropDownTipoComodo(imovel.TipoComodoID);
return View(imovel);
}
//
// POST: /Imoveis/Edit/5
[HttpPost]
public ActionResult Edit(string[] detalhesSelecionados, Imovel imovel, FormCollection formCollection)
{
imovel =
db.Imoveis.Include(i => i.Endereco).Include(i => i.TipoComodo).Include(i => i.DetalhesImovel).Single(
i => i.ImovelID == imovel.ImovelID);
try
{
if (ModelState.IsValid)
{
if (TryUpdateModel(imovel, "", null, new string[] { "DetalhesImovel" }))
{
AtualizaDetalhesImovel(detalhesSelecionados, imovel);
db.Entry(imovel).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
}
}
catch (DbUpdateConcurrencyException ex)
{
var entry = ex.Entries.Single();
var databaseValues = (Imovel)entry.GetDatabaseValues().ToObject();
var clientValues = (Imovel)entry.Entity;
if (databaseValues.TipoComodo.Descricao != clientValues.TipoComodo.Descricao)
ModelState.AddModelError("TipoComodo", "Valor atual: " + databaseValues.TipoComodo.Descricao);
if (databaseValues.QtdComodos != clientValues.QtdComodos)
ModelState.AddModelError("QtdComodos", "Valor atual: " + String.Format("{0:n}", databaseValues.QtdComodos));
if (databaseValues.QtdBanheiros != clientValues.QtdBanheiros)
ModelState.AddModelError("QtdBanheiros", "Valor atual: " + String.Format("{0:n}", databaseValues.QtdBanheiros));
if (databaseValues.Alugado != clientValues.Alugado)
ModelState.AddModelError("Alugado", "Valor atual: " + databaseValues.Alugado);
ModelState.AddModelError(string.Empty, "The record you attempted to edit "
+ "was modified by another user after you got the original value. The "
+ "edit operation was canceled and the current values in the database "
+ "have been displayed. If you still want to edit this record, click "
+ "the Save button again. Otherwise click the Back to List hyperlink.");
imovel.Timestamp = databaseValues.Timestamp;
}
catch (DataException)
{
//Log the error (add a variable name after Exception)
ModelState.AddModelError(string.Empty, "Unable to save changes. Try again, and if the problem persists contact your system administrator.");
}
return View(imovel);
}
//
// GET: /Imoveis/Delete/5
public ActionResult Delete(int id = 0)
{
Imovel imovel = db.Imoveis.Find(id);
if (imovel == null)
{
return HttpNotFound();
}
return View(imovel);
}
//
// POST: /Imoveis/Delete/5
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id)
{
Imovel imovel = db.Imoveis.Find(id);
db.Imoveis.Remove(imovel);
db.SaveChanges();
return RedirectToAction("Index");
}
private void PopularDropDownTipoComodo(object tipoComodoSelecionado)
{
var tipoComodoQuery = from d in db.TipoComodo
orderby d.Descricao
select d
;
ViewBag.TipoComodoId = new SelectList(tipoComodoQuery, "TipoComodoID", "Descricao", tipoComodoSelecionado);
}
private void PopularSeletorDetalhes(Imovel imovel)
{
var todosDetalhes = db.DetalhesImoveis;
var detalhesImovel = new HashSet<int>(imovel.DetalhesImovel.Select(t => t.DetalhesImovelID));
var viewModel = new List<ImovelDetalhes>();
foreach (var detalhe in todosDetalhes)
{
viewModel.Add(new ImovelDetalhes
{
Descricao = detalhe.Descricao,
DetalhesImovelID = detalhe.DetalhesImovelID,
Seletor = detalhesImovel.Contains(detalhe.DetalhesImovelID)
});
}
ViewBag.Detalhes = viewModel;
}
private void AtualizaDetalhesImovel(IEnumerable<string> detalhesSelecionados, Imovel imovelAtualizar)
{
if (detalhesSelecionados == null)
{
imovelAtualizar.DetalhesImovel = new Collection<DetalhesImovel>();
return;
}
var selecaoDetalhesHs = new HashSet<string>(detalhesSelecionados);
var imovelDetalhes = new HashSet<int>(imovelAtualizar.DetalhesImovel.Select(d => d.DetalhesImovelID));
foreach (var item in db.DetalhesImoveis)
{
if (selecaoDetalhesHs.Contains(item.DetalhesImovelID.ToString(CultureInfo.InvariantCulture)))
{
if (!imovelDetalhes.Contains(item.DetalhesImovelID))
{
imovelAtualizar.DetalhesImovel.Add(item);
}
}
else
{
if (imovelDetalhes.Contains(item.DetalhesImovelID))
{
imovelAtualizar.DetalhesImovel.Remove(item);
}
}
}
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}
}
Edit.cshtml:
@model Imobiliario.Models.Imovel
@{
ViewBag.Title = "Editar";
}
<h2>Editar</h2>
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>Imovel</legend>
@Html.HiddenFor(model => model.ImovelID)
@Html.HiddenFor(model => model.Timestamp)
<div class="editor-label">
@Html.LabelFor(model => model.TipoComodo)
</div>
<div class="editor-field">
@Html.DropDownList("TipoComodoID", String.Empty)
@Html.ValidationMessageFor(model => model.TipoComodoID)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.QtdComodos)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.QtdComodos)
@Html.ValidationMessageFor(model => model.QtdComodos)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.QtdBanheiros)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.QtdBanheiros)
@Html.ValidationMessageFor(model => model.QtdBanheiros)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Alugado)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Alugado)
@Html.ValidationMessageFor(model => model.Alugado)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.ValorAluguel)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.ValorAluguel)
@Html.ValidationMessageFor(model => model.ValorAluguel)
</div>
<div class="editor-label">
@Html.Label("Detalhes Imóvel")
</div>
<div class="editor-field">
<table>
<tr>
@{
int cnt = 0;
List<Imobiliario.ViewModels.ImovelDetalhes> detalhes = ViewBag.Detalhes;
foreach (var imovelDetalhes in detalhes)
{
if (cnt++ % 4 == 0)
{
@: </tr> <tr>
}
@: <td>
<input
type="checkbox"
name="detalhesSelecionados"
value="@imovelDetalhes.DetalhesImovelID"@(Html.Raw(imovelDetalhes.Seletor ? "checked=\"checked\"" : ""))/>
@imovelDetalhes.Descricao
@:</td>
}
@: </tr>
}
</table>
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
すべてのメソッドは完全に機能していますが、同時実行性を検証できません。タイムスタンプを使用していますが、変更が加えられ、同時実行に関する警告メッセージが表示されません。
* Q: * 並行性を検証するためのタイムスタンプのバイトが異なる値でロードされることが問題です (ブラウザー A では、表示されるバイトは 0,0,0,0,0,0,8,7 および B です)ブラウザで表示されるバイト数は 0,0,0,0,0,0,23,113) であり、値が異なるため同時実行性は扱われません。誰かが私のコードで私が間違っていることを見ることができますか?
同時実行性をチェックするには、タイムスタンプが同じ値を保持する必要があることを知っています。誰かがこの問題を解決するのを手伝ってくれますか?