我有 2 个表,它们之间存在多对多关系。为了使这种多对多关系发挥作用,我创建了一个新表。这个多对多表只有其他 2 个表的 id:
id_table1
和 id_table2
。
我将数据存储在这个多对多表中,但我在向导中没有看到它,但它存在是因为我有
GetAll
API 和 GetById
API 正在运行。
如何更新此表?
public void Update(T_TPS_PARAMETERS model)
{
_context = new CostingAppDb();
try
{
T_TPS_PARAMETERS oldTpsParameters = _context.T_TPS_PARAMETERS.FirstOrDefault(c => c.TPS_ID == model.TPS_ID);
decimal oldTpsParametersId = oldTpsParameters.TPS_ID;
foreach (var company in model.T_COMPANY)
{
T_COMPANY oldCompany = _context.T_COMPANY.FirstOrDefault(c => c.ID_COMPANY == company.ID_COMPANY);
decimal oldCompanyId = oldCompany.ID_COMPANY;
UpdateRelationship(oldCompanyId, oldTpsParametersId, company.ID_COMPANY, model.TPS_ID);
}
_context.Entry(model).State = System.Data.Entity.EntityState.Modified;
_context.SaveChanges();
}
catch (Exception ex)
{
throw ex;
}
}
private void InsertWithData(decimal companyId, decimal tpsId)
{
T_COMPANY c = new T_COMPANY { ID_COMPANY = companyId };
_context.T_COMPANY.Add(c);
_context.T_COMPANY.Attach(c);
T_TPS_PARAMETERS psd = new T_TPS_PARAMETERS { TPS_ID = tpsId };
_context.T_TPS_PARAMETERS.Add(psd);
_context.T_TPS_PARAMETERS.Attach(psd);
c.T_TPS_PARAMETERS.Add(psd);
_context.SaveChanges();
}
public void DeleteRelationship(decimal companyId, decimal tpsId)
{
var company = _context.T_COMPANY.FirstOrDefault(c => c.ID_COMPANY == companyId);
var tpsParameter = _context.T_TPS_PARAMETERS.FirstOrDefault(p => p.TPS_ID == tpsId);
company.T_TPS_PARAMETERS.Remove(tpsParameter);
_context.SaveChanges();
}
public void UpdateRelationship(decimal oldCompanyId, decimal oldTpsId, decimal newCompanyId, decimal newTpsId)
{
DeleteRelationship(oldCompanyId, oldTpsId);
InsertWithData(newCompanyId, newTpsId);
}
这是我得到的错误:
System.Data.Entity.Infrastruct.DbUpdateException:“保存未公开其关系的外键属性的实体时发生错误。 EntityEntries 属性将返回 null,因为无法将单个实体标识为异常源。通过在实体类型中公开外键属性,可以更轻松地处理保存时的异常。有关详细信息,请参阅 InnerException。'
InvalidOperationException:表/视图没有定义主键。该实体是只读的
使用EF,多对多连接表可以显式映射到实体,也可以隐式映射。在大多数情况下,如果连接表只是将两者链接起来,那么使用隐式映射会更简单。例如隐式映射:
public class A
{
// ...
public virtual ICollection<B> Bs { get; } = [];
}
public class B
{
// ...
public virtual ICollection<A> As { get; } = [];
}
vs explicit:
public class A
{
// ...
public virtual ICollection<AB> ABs { get; } = [];
}
public class B
{
// ...
public virtual ICollection<AB> ABs { get; } = [];
}
public class AB
{
public virtual A A { get; set; }
public virtual B B { get; set; }
}
删除关联时,无论哪种情况,您都可以通过关联的导航属性来执行此操作。在您的情况下,DeleteRelationship 方法应该类似于:
public void DeleteRelationship(decimal companyId, decimal tpsId)
{
var company = _context.T_COMPANY
.Include(c => c.TPS_PARAMETERS)
.Single(c => c.ID_COMPANY == companyId);
var tpsParameter = company.TPS_PARAMETERS.FirstOrDefault(p => p.TPS_ID == tpsId);
if (tpsParameter != null)
{
company.T_TPS_PARAMETERS.Remove(tpsParameter);
_context.SaveChanges();
}
}
如果您在提取中添加
.Include(c => c.TPS_PARAMETERS)
,那么您的代码也会起作用,前提是从数据库提取的参数位于公司的参数列表中。
每当从一对多或多对多的关联中添加或删除项目时,您应该始终确保相关实体已加载。这样,EF 就可以利用更改跟踪代理来确定添加或删除关联时要执行的操作。