gpt4 book ai didi

c# - 一对一识别关系的 Entity Framework Code First Fluent API 配置

转载 作者:太空狗 更新时间:2023-10-30 01:18:17 27 4
gpt4 key购买 nike

我有以下类结构:

enter image description here

如何配置 Fluent API 将标识关系放入 Cards 表中?

我是说

  • 卡片表 PK:Id,CustomerId
  • 卡片表 FK:CustomerId

当我为 Customer.Card 属性分配新的 Card 时,我希望删除以前的 Card。

所以我这样定义我的类:

public class Customer
{
public int Id { get; private set; }
public virtual Card Card { get; set; }
}

public abstract class Card
{
public int Id { get; private set; }
}

public class Visa : Card
{
}

public class Amex : Card
{
}

DbContext 看起来像这样:

public class Context : DbContext
{
public DbSet<Customer> Customers { get; set; }
public DbSet<Card> Cards { get; set; }

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);

modelBuilder.Entity<Customer>()
.HasRequired(c => c.Card)
.WithRequiredPrincipal()
.Map(a => a.MapKey("CustomerId"))
.WillCascadeOnDelete();

modelBuilder.Entity<Card>();
}
}

这是测试:

[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var context = new Context();
var customer = new Customer();
context.Customers.Add(customer);
customer.Card = new Visa();
context.SaveChanges();

customer.Card = new Amex();
context.SaveChanges();

Assert.AreEqual(1, context.Customers.Count());
Assert.AreEqual(1, context.Cards.Count());
}
}

它根本不起作用。我在第二次保存时有这个,我不知道如何在这里指定识别关系:

Unhandled Exception: System.Data.Entity.Infrastructure.DbUpdateException: An err or occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a singl e entity cannot be identified as the source of the exception. Handling of except ions while saving can be made easier by exposing foreign key properties in your entity types. See the InnerException for details. ---> System.Data.Entity.Core.U pdateException: A relationship from the 'Customer_Card' AssociationSet is in the 'Deleted' state. Given multiplicity constraints, a corresponding 'Customer_Card _Target' must also in the 'Deleted' state.

更新 使其适用于一对多关系很容易。您可以在下面找到完整的示例:

[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var context = new Context();
var customer = new Customer();
context.Customers.Add(customer);
customer.Cards.Add(new Visa());
context.SaveChanges();

customer.Cards[0] = new Amex();
context.SaveChanges();

Assert.AreEqual(1, context.Cards.Count());
}
}

public class Customer
{
public Customer()
{
Cards = new List<Card>();
}

public int Id { get; private set; }
public virtual List<Card> Cards { get; set; }
}

public abstract class Card
{
public int Id { get; private set; }
public int CustomerId { get; private set; }
}

public class Visa : Card
{
}

public class Amex : Card
{
}

public class Context : DbContext
{
static Context()
{
Database.SetInitializer(new DropCreateDatabaseAlways<Context>());
}

public DbSet<Customer> Customers { get; set; }
public DbSet<Card> Cards { get; set; }

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);

modelBuilder.Entity<Customer>()
.HasMany(c => c.Cards)
.WithRequired()
.HasForeignKey(c => c.CustomerId)
.WillCascadeOnDelete();

modelBuilder.Entity<Card>()
.HasKey(c => new { c.Id, c.CustomerId });
}
}

最佳答案

EF 实现一对一的方式是让依赖实体有一个主键,这个主键也是主体实体的外键。所以依赖者的PK自然受限于现有的原则PK值。

所以使用你的类,稍微修改一下:

public class Customer
{
public int CustomerId { get; private set; }
public virtual Card Card { get; set; }
}

public abstract class Card
{
public int CustomerId { get; private set; }
}

public class Visa : Card { }

public class Amex : Card { }

和映射:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Customer>().HasRequired(c => c.Card)
.WithRequiredPrincipal();
modelBuilder.Entity<Card>().HasKey(c => c.CustomerId);
}

因此 Card 只有 CustomerId 作为 PK FK,而不是两个单独的字段。

但是

通过尝试,我发现 EF (6.1.2) 中存在错误。这就是我所做的:

using (var db = new TempModelsContext())
{
var cst = new Customer { Name = "Customer1",
Card = new Amex { Number = "Amex" } };
db.Customers.Add(cst);
db.SaveChanges();
}

using (var db = new TempModelsContext())
{
var cst = db.Customers.Include(c => c.Card).Single(c => c.CustomerId == 1);
cst.Card = new Visa { Number = "Visa" };
db.SaveChanges();
}

(为方便起见添加了NameNumber)。

通常这样就可以了。 EF 足够聪明,可以看到 1:1 依赖实体已被替换,它只是更新 Number 字段(有效删除旧卡)。

但是 EF 忽略了继承(为此我使用了默认值 TPH)。当然它也应该更新鉴别器字段,但它没有。如果您从数据库中重新获取项目,您最终会得到一张 Amex 卡,其编号为“Visa”。

所以,遗憾的是,即使使用这个模型,您也必须先移除旧卡,然后再添加新卡:

var cst = db.Customers.Include(c => c.Card).Single(c => c.CustomerId == 1);
db.Cards.Remove(cst.Card);
db.SaveChanges();

cst.Card = new Visa { Number = "Visa" };
db.SaveChanges();

这已经够笨拙的了,更不用说您还想将其包装在 TransactionScope 中。

关于c# - 一对一识别关系的 Entity Framework Code First Fluent API 配置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28006842/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com