我正在跟踪互联网上的示例,但没有用。数据库创建成功,没有错误。
我要拥有的是:一个用户可以有多个交易,而一个交易可以有两个用户的引用。其中一个是进行交易的用户,第二个是进行交易的用户。
但是发生的事情是我在Users表中得到了三个外键,而在Transaction表中却没有。
请参见下图:
我的课程
public class User
{
public int userId { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string CardNumber { get; set; }
public string Password { get; set; }
public int Balance { get; set; }
public string UserType { get; set; }
public string ProfileUrl { get; set; }
public IList<Transaction> Transactions { get; set; }
}
public class Transaction
{
public Transaction()
{
this.TranscationDateTime = DateTime.UtcNow;
}
public int TransactionId { get; set; }
public int Amount { get; set; }
public User FromUser { get; set; }
public User ToUser { get; set; }
public DateTime TranscationDateTime { get; set; }
}
public class DB: DbContext
{
public DB() : base("name=DBConnection")
{ }
public DbSet<User> Users { get; set; }
public DbSet<Transaction> Transactions { get; set; }
}
答案 0 :(得分:1)
您需要对代码进行一些修改。
首先,每个导航属性都需要标记为virtual,以便允许Entity Framework延迟加载,除非您希望始终渴望加载所有导航(可以选择,取决于您)。
此后,您的每个用户都有outgoing
和incoming
个交易,因此对于User
类:
public class User
{
public int userId { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string CardNumber { get; set; }
public string Password { get; set; }
public int Balance { get; set; }
public string UserType { get; set; }
public string ProfileUrl { get; set; }
public virtual IList<Transaction> IncomingTransactions { get; set; }
public virtual IList<Transaction> OutgoingTransactions { get; set; }
}
让我们创建Transaction
类的虚拟导航属性
public class Transaction
{
public Transaction()
{
this.TranscationDateTime = DateTime.UtcNow;
}
public int TransactionId { get; set; }
public int Amount { get; set; }
public virtual User FromUser { get; set; }
public virtual User ToUser { get; set; }
public DateTime TranscationDateTime { get; set; }
}
最后但并非最不重要的一点是,让我们通知DbContext应该如何进行:
public class MyContext : DbContext
{
public MyContext(string connectionString) : base(connectionString) { }
public DbSet<User> Users { get; set; }
public DbSet<Transaction> Transactions { get; set; }
protected override void OnModelCreating(DbModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<Transaction>()
.HasRequired<User>(t => t.FromUser)
.WithMany(u => u.OutgoingTransactions).WillCascadeOnDelete(false);
builder.Entity<Transaction>()
.HasRequired<User>(t => t.ToUser)
.WithMany(u => u.IncomingTransactions).WillCascadeOnDelete(false);
}
}
这对于EF自动发现应该足以做出正确的假设并创建正确的数据库结构,这将是Transaction表中的两个FK,每个FK都是Users表的主键。
答案 1 :(得分:0)
我要拥有的一个用户可以有多个交易,但是一个交易可以引用两个用户。
您当前的数据库模型正确地反映了这一点。我将在其余答案中解释原因。
User
表不能保存Transactions
表的外键,因为一个用户可以与多个事务关联。如果FK列位于“用户”表上,则它将需要保存多个TransactionID。
相反,对用户的引用存储在Transaction
表中。因此,每个事务只需要为每个FK列存储一个UserId。
Transaction.User_userId
告诉我们此交易位于用户IList<Transaction> Transactions
中,其中存储了User_userId
。
要获取特定用户的交易列表,请查询
SELECT *
FROM Transactions t
INNER JOIN Users u on t.User_userId = u.userId
WHERE u.userId = {theUserId}
存在其他FK ToUser_userId
和FromUser_userId
是因为它们可能引用了不同的用户。
如果IList<Transaction> Transactions
的语义实际上是“源自该用户的所有事务”,则可以将ModelBuilder配置为对该集合使用FromUser_userId
FK,而不用创建第三个FK {{ 1}}。看到谢尔盖的答案。
答案 2 :(得分:0)
之所以会这样,是因为EF不知道FromUser
和ToUser
字段之一应该与集合Transactions
相匹配-因为您没有关注naming conventions 。您可以通过多种方法来解决这种情况:
Transactions
集合与 FromUser
或ToUser
而不是两者都匹配,则可以使用[ForeignKey]
和/或[InverseProperty]
个属性以显式设置数据库关系User
类中指定两个集合-例如TransactionsFromUser
和TransactionsToUser
。您可能仍然需要通过属性来显式设置关系