C# 简化实体框架6一对一关系的语法
在断开连接的模型中使用Entity Framework 6的Web应用程序中,我有两个具有一对一关系的表: 借贷者表C# 简化实体框架6一对一关系的语法,c#,entity-framework,entity-framework-6,C#,Entity Framework,Entity Framework 6,在断开连接的模型中使用Entity Framework 6的Web应用程序中,我有两个具有一对一关系的表: 借贷者表 借用ID(主键和FK) 商业名称 [删除其他列以保持示例简单] 借阅个人表格 借用ID(主键和FK) 全名 [删除其他列以保持示例简单] FK关系位于借用ID上。总是有借贷者记录,但偶尔也有借贷者个人记录。我已在关系上定义了级联删除 在代码中,我有以下内容(我删除了属性以保持示例的简单性): 在我的repository类中,我有以下CRUD操作: public class
- 借用ID(主键和FK)
- 商业名称
- [删除其他列以保持示例简单]
- 借用ID(主键和FK)
- 全名
- [删除其他列以保持示例简单]
public class BusinessBorrowerRepository
{
public Borrower GetById(int id)
{
Borrower item;
using (var db = new MainContext())
{
item = db.Borrowers
.Include(b => b.BorrowerIndividual)
.FirstOrDefault(f => f.Id == id);
}
return item;
}
public int Add(Borrower entity)
{
int id;
using (var db = new MainContext())
{
db.Entry(entity).State = EntityState.Added;
db.SaveChanges();
id = (int)entity.Id;
}
return id;
}
public bool Update(Borrower entity)
{
using (var db = new MainContext())
{
if (entity.BorrowerIndividual != null)
{
entity.BorrowerIndividual.Id = entity.Id; // share same key, set to match
// Test if record exists in db to determine if added or modified
var exists = db.BorrowerIndividuals.Any(i => i.Id == entity.BorrowerIndividual.Id.Value);
db.Entry(entity.BorrowerIndividual).State = exists ? EntityState.Modified : EntityState.Added;
}
db.Entry(entity).State = EntityState.Modified;
db.SaveChanges();
}
return true;
}
public bool Delete(int id)
{
using (var db = new MainContext())
{
var entity = GetById(id);
if (entity.BorrowerIndividual != null)
{
db.BorrowerIndividuals.Attach(entity.BorrowerIndividual);
db.BorrowerIndividuals.Remove(entity.BorrowerIndividual);
entity.BorrowerIndividual = null;
}
db.Borrowers.Attach(entity);
db.Borrowers.Remove(entity);
db.SaveChanges();
}
return true;
}
}
DbContext类:
internal class MainContext : DbContext
{
internal MainContext() : base("name=SqlServer")
{
Database.SetInitializer<MainContext>(null);
}
public virtual DbSet<Borrower> Borrowers { get; set; }
public virtual DbSet<BorrowerIndividual> BorrowerIndividuals { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer<MainContext>(null);
modelBuilder.Configurations.Add(new BorrowerConfiguration());
base.OnModelCreating(modelBuilder);
}
}
class BorrowerConfiguration : EntityTypeConfiguration<Borrower>
{
internal BusinessBorrowerConfiguration()
{
this.HasRequired(x => x.BorrowerIndividual).WithRequiredPrincipal();
}
}
内部类MainContext:DbContext
{
内部MainContext():base(“name=SqlServer”)
{
Database.SetInitializer(null);
}
公共虚拟数据库集{get;set;}
公共虚拟数据库集借用者个人{get;set;}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
Database.SetInitializer(null);
modelBuilder.Configurations.Add(新的借用配置());
基于模型创建(modelBuilder);
}
}
类借用配置:EntityTypeConfiguration
{
内部BusinessBorrowerConfiguration()
{
this.HasRequired(x=>x.BorrowerIndividual).WithRequiredPrincipal();
}
}
GetById和Add看起来非常典型。更新和删除似乎过于冗长。我能做些什么来允许:
总的来说,似乎要让它发挥作用需要做更多的工作 两种方法都可以简化。但首先确保级联删除已启用(因为默认情况下它不是): 但请注意,如果没有具有指定的
Id
的记录,它将异常失败。因此,更安全的版本是这样的(不要使用使用不同上下文的GetById
方法,也不要包含相关数据,因为我们将依赖数据库级联删除):
更新:
这适用于借用个人修改的所有场景(null
到new
-插入,现有到null
,删除,现有到现有更新)。唯一的缺点是,在最后一种情况下,即使没有更改任何属性,它也总是为借款者个人
生成更新
命令。因此,如果您想以多出几行代码的代价优化数据库命令,可以使用以下方法:
var existing = db.Borrowers.Include(e => e.BorrowerIndividual).FirstOrDefault(e => e.Id == entity.Id);
db.Entry(existing).CurrentValues.SetValues(entity);
if (existing == null) return; // ??
if (existing.BorrowerIndividual != null && entity.BorrowerIndividual != null)
{
entity.BorrowerIndividual.Id = existing.Id;
db.Entry(existing.BorrowerIndividual).CurrentValues.SetValues(entity.BorrowerIndividual);
}
else
existing.BorrowerIndividual = entity.BorrowerIndividual;
db.SaveChanges();
在EF中处理断开连接的实体从来都不容易。使用级联删除,通过不使用GetById
,而是使用db
变量或仅使用存根实体,可以简化delete
方法。对于Update
,您没有其他选择,因为您正在接收分离的对象。我尝试不使用GetById,而只是附加到仅具有Id的对象的新实例。问题是,由于需要先删除相关的借阅行,我在保存时遇到FK错误。我还必须添加entity.BorrowerIndividual=null行,否则它可能会抱怨SaveChanges。似乎比应该做的还要多。我有一个将此对象作为属性的父对象,以及其他子对象,因此更新和删除非常长。创建存储过程可能更有意义,它将尊重SQL中的级联删除代码>和var entity=db.借款人.FirstOrDefault(e=>e.Id==Id);db.借款人。移除(实体)代码>为我工作。但是请注意,由于发布的安装程序没有激活cascade delete,我必须在调用WithRequiredPrincipal()
之后添加。Willcascade ondelete()
。@IvanStoev,这确实清除了删除!由于我没有收到任何关于更新的其他反馈,如果您将此作为答案发布,我可以接受,因为它清除了我的删除。您对ASP.NET MVC to SQL的更好的ORM有什么建议吗?在过去4年中,我在大约6个应用程序上使用了EF,在此之前,我使用了MS Enterprise Library数据访问应用程序块和存储过程。EL并不是一个真正的ORM,但我确实节省了大量重复的ADO.NET调用。尽管仍有大量无意识的重复工作在构建CRUD存储过程,并映射所有属性。不。唯一的竞争对手是NHibernate,但IMO EF更直观。查询部分很好,CRUD将很容易跟踪上下文的服务。唯一困难的是使用断开连接的实体/DTO的CRUD,但通过一些重复代码,一切都可以解决。有一个开源软件包正在解决最后一个问题,但不幸的是,它不再受支持。我尝试了第二个更新建议,但它引发了以下异常:EntityFramework.dll中发生了类型为“System.InvalidOperationException”的异常,但未在用户代码中处理。其他信息:属性“Id”是对象密钥信息的一部分,无法删除被改进的。在以下行:db.Entry(现有).CurrentValues.SetValues(实体);我弄明白了,需要过滤记录:var existing=db.fourses.Include(e=>e.fourneridividual).FirstOrDefault(e=>e.Id==entity.Id);我更新了你的答案以反映这一变化。绝对-这正是我在发帖前的想法和测试,但忘了把它放进去
modelBuilder.Entity<Borrower>()
.HasRequired(x => x.BorrowerIndividual)
.WithRequiredPrincipal()
.WillCascadeOnDelete();
db.Entry(new Borrower { Id = id }).State = EntityState.Deleted;
db.SaveChanges();
var existing = db.Borrowers.FirstOrDefault(e => e.Id == id);
if (existing == null) return; // ??
db.Borrowers.Remove(existing);
db.SaveChanges();
var existing = db.Borrowers.Include(e => e.BorrowerIndividual).FirstOrDefault(e => e.Id == entity.Id);
if (existing == null) return; // ??
db.Entry(existing).CurrentValues.SetValues(entity);
existing.BorrowerIndividual = entity.BorrowerIndividual;
db.SaveChanges();
var existing = db.Borrowers.Include(e => e.BorrowerIndividual).FirstOrDefault(e => e.Id == entity.Id);
db.Entry(existing).CurrentValues.SetValues(entity);
if (existing == null) return; // ??
if (existing.BorrowerIndividual != null && entity.BorrowerIndividual != null)
{
entity.BorrowerIndividual.Id = existing.Id;
db.Entry(existing.BorrowerIndividual).CurrentValues.SetValues(entity.BorrowerIndividual);
}
else
existing.BorrowerIndividual = entity.BorrowerIndividual;
db.SaveChanges();