asp.net 外键属性“”是在阴影状态下创建的,因为简单名称为“”的属性与此冲突

trnvg8h3  于 2022-11-19  发布在  .NET
关注(0)|答案(2)|浏览(134)

整个错误:
外键属性“Appointment.CustomerId1”是在阴影状态下创建的,因为实体类型中存在简单名称为“CustomerId”的冲突属性,但该属性未Map、已用于另一个关系或与关联的主键类型不兼容。
数据表:
Appointment
User
在“预约”表中,我有2个FK:一个指向Customer表(Id列),另一个添加到Employee表(Id列)。请参见BEFORE部分的图片。但现在,因为我将所有用户(customer + employee)在同一个表User中,它必须改变。这意味着在Appointment表中我需要有2个FK,但它们都需要指向同一个表User,和“ID”列。我希望CustomerId和EmployeeId指向来自用户的ID。
它会建立3个额外的数据行:UserId、CustomerId 1和EmployeeId 1--我不需要它们。我只对关系使用了Conventions,没有使用Data Annotations或Fluent API。
有3种情况可能导致错误:

  1. 1.未Map
  2. 1.已用于另一关系
  3. 1.与关联的主键类型不兼容
    据我了解
  4. 1.不是我的情况,因为数据类型是相同的(字符串)。
  5. 1.不是我的案子,因为我没有其他关系。
  6. 1.可能有问题,但我不确定。我可能需要为这个Map添加一些Fluent Api。这是我尝试过的,但它不起作用:https://i.stack.imgur.com/UFrC6.png
    双向方法:
    使用者类别:
public ICollection<Appointment> AppointmentCustomers { get; set; }
public ICollection<Appointment> AppointmentEmployees { get; set; }

预约类别:

public string CustomerId { get; set; }
[ForeignKey("CustomerId")]
public User Customer { get; set; }

public string EmployeeId { get; set; }
[ForeignKey("EmployeeId")]
public User Employee { get; set; }

OnModel创建方法:

builder.Entity<Appointment>()
    .HasOne(u => u.Customer)
    .WithMany(app => app.AppointmentCustomers)
    .HasForeignKey(u => u.CustomerId)
    .OnDelete(DeleteBehavior.NoAction);

builder.Entity<Appointment>()
    .HasOne(u => u.Employee)
    .WithMany(app => app.AppointmentEmployees)
    .HasForeignKey(u => u.EmployeeId)
    .OnDelete(DeleteBehavior.NoAction);
bf1o4zei

bf1o4zei1#

以前,EF可以通过约定来计算键。约定基于类型名称(Employee vs. Customer)而不是变量名称。如果您将外键命名为EmployeeKey/EmpID和CustomerKey/CustID,您将遇到类似的问题。EF的约定不会将它们作为外键关联,因此它将创建影子属性。
现在您将这两个属性都指向同一个Type(User)EF不能使用约定,所以您必须显式地使用。解决这个问题最简单的方法是使用[ForeignKey]属性。这可以放在FK属性上以指向navigation属性,也可以放在navigation属性上以指向FK。

[ForeignKey(nameof(Customer))]
public string CustomerId { get; set; }
[ForeignKey(nameof(Employee))]
public string EmployeeId { get; set; }

public virtual User Customer { get; set; }
public virtual User Employee { get; set; }

public string CustomerId { get; set; }
public string EmployeeId { get; set; }

[ForeignKey(nameof(CustomerId))]
public virtual User Customer { get; set; }
[ForeignKey(nameof(EmployeeId))]
public virtual User Employee { get; set; }

编辑:
您现在得到的错误是因为用户有一个约会集合,但您必须告诉EF此FK链接到哪个集合。这里您有一个约会,它引用了两个用户,一个客户和一个员工。从用户的Angular 来看,有两个不同的关系。“约会-我是客户”和“约会-我是员工”。
如果您只对一种关系感兴趣,则需要配置EF以基于“约会客户”或“员工”关系Map“用户.约会.”如果您对两种关系都感兴趣,则有两个选项.
a)向User添加2个Appointments集合,即AppointmentsAsCustomer和AppointmentsAsEmployee,并在模型构建器或EntityTypeConfiguration中设置Map。b)删除User上的Appointments集合,并使用.HasOne(x => x.Customer).WithMany().HasOne(x => x.Employee).WithMany()配置EF,然后当您希望按用户查询约会时,从Appointments执行此操作,而不是期望通过User进行导航:
而不是:

var appointmentsForUser = context.Users
    .Where(u => u.UserId == userId)
    .SelectMany(u => u.Appointments) // can't work for both asEmployee and asCustomer
    .ToList();

用途:

var appointmentsForUser = context.Appointments
    .Where(a => a.Customer.UserId == userId 
       || a.Employee.UserId == userId) // if you want appts where user is customer or employee
    .ToList();

双向引用(其中约会引用用户,而用户引用约会)应仅在绝对需要时而非默认情况下谨慎使用。它们可能导致更新时的怪异行为以及延迟加载的含义,以及像这样的具有模糊关系的“陷阱”。

w9apscun

w9apscun2#

该属性已用于旧的Customer和Employee类中的另一个关系。
Steve Py's answer在外键配置方面有很大帮助,但从我所读到的内容来看,最好通过Fluent API与Data Annotations进行配置。)

相关问题