我想更新我使用Code First在實體框架中設置的多對多關係。我創建了以下模型。無法更新多對多關係。實體框架代碼第一
[Serializable]
public class ClientFormField : FormField
{
public ClientFormField()
{
CanDisable = true;
}
public virtual ClientFormGroup Group { get; set; }
public virtual ICollection<ClientValue> Values { get; set; }
public virtual ICollection<LetterTemplate> LetterTemplates { get; set; }
}
[Serializable]
public class CaseFormField : FormField
{
public CaseFormField()
{
CanDisable = true;
}
public virtual CaseFormGroup Group { get; set; }
public virtual ICollection<LetterTemplate> LetterTemplates { get; set; }
public override IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
foreach (var val in base.Validate(validationContext))
yield return val;
}
}
[Serializable]
public class SystemField : TrackableEntity
{
public string Name { get; set; }
public string Value { get; set; }
public string VarName { get; set; }
public virtual SystemFieldType SystemFieldType { get; set; }
public int TypeId { get; set; }
public ICollection<LetterTemplate> LetterTemplates { get; set; }
public override IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (string.IsNullOrWhiteSpace(Name))
yield return new ValidationResult("System field must have a name.", new[] { "SystemFieldName" });
if (string.IsNullOrWhiteSpace(Value))
yield return new ValidationResult("System field must have a value.", new[] { "SystemFieldValue" });
var regex = new Regex(@"^[a-zA-Z0-9-_]+$");
if (!string.IsNullOrWhiteSpace(VarName) && !regex.IsMatch(VarName))
yield return
new ValidationResult("Varname can only contain alphanumeric, underscore, or hyphen",
new[] { "SystemFieldVarName" });
if (TypeId <= 0)
yield return new ValidationResult("System Field must have a type.", new[] { "SystemFieldType" });
}
}
[Serializable]
public class LetterTemplate : TrackableEntity
{
public LetterTemplate()
{
ClientFields = new Collection<ClientFormField>();
CaseFields = new Collection<CaseFormField>();
SystemFields = new Collection<SystemField>();
}
public string Name { get; set; }
public string Data { get; set; }
public virtual ICollection<ClientFormField> ClientFields { get; set; }
public virtual ICollection<CaseFormField> CaseFields { get; set; }
public virtual ICollection<SystemField> SystemFields { get; set; }
public override IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if(string.IsNullOrWhiteSpace(Name))
yield return new ValidationResult("Form Template must have a name", new[] { "Name" });
if(string.IsNullOrWhiteSpace(Data))
yield return new ValidationResult("Form Template must have content", new[] { "Data" });
}
}
以下是LetterTemplate類的配置。
public class LetterTemplateConfiguration : BaseTrackableEntityConfiguration<LetterTemplate>
{
public LetterTemplateConfiguration()
{
HasMany(c => c.ClientFields).WithMany(c => c.LetterTemplates)
.Map(m =>
{
m.MapLeftKey("LetterTemplateId");
m.MapRightKey("ClientFormFieldId");
m.ToTable("LetterTemplateClientFields");
});
HasMany(c => c.CaseFields).WithMany(c => c.LetterTemplates)
.Map(m =>
{
m.MapLeftKey("LetterTemplateId");
m.MapRightKey("CaseFormFieldId");
m.ToTable("LetterTemplateCaseFields");
});
HasMany(c => c.SystemFields).WithMany(c => c.LetterTemplates)
.Map(m =>
{
m.MapLeftKey("LetterTemplateId");
m.MapRightKey("SystemFieldId");
m.ToTable("LetterTemplateSystemFields");
});
}
}
這裏是添加/更新控制方法和保持業務邏輯添加/更新
[HttpPost]
[ValidateAntiForgeryToken]
[ValidateInput(false)]
public ActionResult Manage(LetterTemplate template)
{
if(ModelState.IsValid)
{
if (_letterTemplateService.Save(template) != null)
return RedirectToAction("List");
}
ViewBag.ClientFields = _clientFieldService.GetAllFields().OrderBy(f => f.Name);
ViewBag.CaseFields = _caseFieldService.GetAllFields().OrderBy(f => f.Name);
ViewBag.SystemFields = _systemFieldService.GetAllFields().OrderBy(f => f.Name);
return View(template);
}
public LetterTemplate Save(LetterTemplate template)
{
var dbTemplate = template;
if (template.Id > 0)
{
dbTemplate = _letterTemplateRepo.GetById(template.Id);
dbTemplate.Name = template.Name;
dbTemplate.Data = template.Data;
}
dbTemplate.ClientFields.Clear();
foreach (var field in _clientFieldRepo.All().Where(field => template.Data.Contains("~~" + field.VarName + "~~")))
dbTemplate.ClientFields.Add(field);
dbTemplate.CaseFields.Clear();
foreach (var field in _caseFieldRepo.All().Where(field => template.Data.Contains("~~" + field.VarName + "~~")))
dbTemplate.CaseFields.Add(field);
dbTemplate.SystemFields.Clear();
foreach (var field in _systemFieldRepo.All().Where(field => template.Data.Contains("~~" + field.VarName + "~~")))
dbTemplate.SystemFields.Add(field);
return template.Id <= 0 ? _letterTemplateRepo.Add(dbTemplate) : _letterTemplateRepo.Update(dbTemplate);
}
這裏是信函模板的添加/更新視圖中的服務器的方法。
@section RightContent
{
<h4>Manage</h4>
<form method="POST" action="/LetterTemplate/Manage" id="templateForm">
<div id="toolbar">
<div style="float: left;padding: 3px 0px 0px 10px;">
@Html.LabelFor(m => m.Name)
@Html.TextBoxFor(m => m.Name)
</div>
<div class="item" onclick=" $('#templateForm').submit(); ">
<span class="save"></span>Save
</div>
<div class="item" onclick=" window.location = '/LetterTemplate/List'; ">
<span class="list"></span>Back To List
</div>
</div>
<div class="formErrors">
@Html.ValidationSummary()
</div>
@Html.HiddenFor(m => m.Id)
@Html.HiddenFor(m => m.Active)
@Html.HiddenFor(m => m.IsDeleted)
@Html.TextAreaFor(m => m.Data)
@Html.AntiForgeryToken()
</form>
}
當我從視圖中創建一個新的模板時,一切工作正常。正如我所期望的,我在我的多對多關係表中填充字段。當我試圖更新應該清除所有現有關係並建立新關係的關係時,什麼都不會發生。表格完全不受影響。我已經閱讀了幾篇關於更新許多表的問題的不同文章,但沒有找到任何解決我的問題的內容。這是我第一次用EF代碼第一次嘗試了很多很多,並且事先遵循了許多教程,但似乎無論我做什麼,EF都不會更新關係表。
UPDATE:
DECLARE @0 nvarchar = N'Test',
@1 nvarchar = N'<p>~~case_desc~~</p>
<p>~~fname~~</p>
<p>~~lname~~</p>
',
@2 bit = 1,
@3 bit = 0,
@4 int = 2,
@5 int = 2,
@6 DateTime2 = '2013-04-08T16:36:09',
@7 DateTime2 = '2013-04-08T16:36:09'
insert [dbo].[LetterTemplates]([Name], [Data], [Active], [IsDeleted], [CreatedById], [ModifiedById], [DateCreated], [DateModified])
values (@0, @1, @2, @3, @4, @5, @6, @7)
DECLARE @0 int = 2,
@1 int = 1
insert [dbo].[LetterTemplateClientFields]([LetterTemplateId], [ClientFormFieldId])
values (@0, @1)
DECLARE @0 int = 2,
@1 int = 2
insert [dbo].[LetterTemplateClientFields]([LetterTemplateId], [ClientFormFieldId])
values (@0, @1)
DECLARE @0 int = 2,
@1 int = 3
insert [dbo].[LetterTemplateClientFields]([LetterTemplateId], [ClientFormFieldId])
values (@0, @1)
查詢生成的更新:增加一個新的模板時產生
查詢
DECLARE @0 nvarchar = N'Test',
@1 nvarchar = N'<p>~~case_desc~~</p>
<p> </p>
<p>~~fname~~</p>
<p> </p>
<p>~~dob~~</p>
',
@2 bit = 1,
@3 bit = 0,
@4 int = 2,
@5 int = 2,
@6 DateTime2 = '2013-04-08T16:23:12',
@7 DateTime2 = '2013-04-08T16:33:15',
@8 int = 1
update [dbo].[LetterTemplates]
set [Name] = @0, [Data] = @1, [Active] = @2, [IsDeleted] = @3, [CreatedById] = @4, [ModifiedById] = @5, [DateCreated] = @6, [DateModified] = @7
where ([Id] = @8)
UPDATE
我的存儲庫模式有2個基本泛型類。基礎可跟蹤實體庫和基礎庫。基本可跟蹤實體回購處理確保刪除的項目被軟刪除,獲取未刪除的項目,並管理createdby/modifiedby和createdDate/UpdatedDate。基本倉庫處理其餘的基本CRUD操作。以下是我在通過LetterTemplateRepository調用更新時調用的更新方法和關聯方法。由於此repo繼承基本可跟蹤實體repo,因此它將從基類中運行更新。
public override T Update(T entity)
{
return Update(entity, false);
}
public override T Update(T entity, bool attachOnly)
{
InsertTeData(ref entity);
entity.ModifiedById = CurrentUserId;
entity.DateModified = DateTime.Now;
_teDB.Attach(entity);
_db.SetModified(entity);
if (!attachOnly) _db.Commit();
return entity;
}
private void InsertTeData(ref T entity)
{
if (entity == null || entity == null) return;
var dbEntity = GetById(entity.Id);
if (dbEntity == null) return;
_db.Detach(dbEntity);
entity.CreatedById = dbEntity.CreatedById;
entity.DateCreated = dbEntity.DateCreated;
entity.ModifiedById = dbEntity.ModifiedById;
entity.DateModified = dbEntity.DateModified;
}
DbContext中的SetModified方法只是將EntityState設置爲Modified。我在單元測試中使用了一個假DbContext和DbSet,所以我通過DbContext擴展了任何EF特定的調用,以允許我的測試工作而無需創建一堆假庫。
你的'_letterTemplateRepo.Update()'方法是做什麼的? – 2013-04-09 01:23:35
我更新了我的問題,並將更新方法調用到我的存儲庫類中。 – DSlagle 2013-04-09 01:42:48
你可以嘗試一個實驗嗎? '_letterTemplateRepo.Update(dbTemplate)'用'_letterTemplateRepo.Save()'替換,它將簡單地調用'_db.SaveChanges()'。 – 2013-04-09 19:11:13