我在 .NET Core 应用程序中使用 Entity Framework Core,但遇到了一些奇怪的问题。当我尝试检索以前保存的对象时,该对象的主键为空,即使它是在数据库中设置的。
示例/代码:
public class Context : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<UserData> UserDatas { get; set; }
public DbSet<Session> Sessions { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
CreateRelationships(modelBuilder);
CreateIndexs(modelBuilder);
}
private void CreateRelationships(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasOne(e => e.UserData)
.WithOne(e => e.User)
.HasForeignKey<UserData>(e => e.UserID)
.IsRequired();
modelBuilder.Entity<User>()
.HasOne(e => e.Session)
.WithOne(e => e.User)
.HasForeignKey<Session>(e => e.UserID)
.IsRequired();
modelBuilder.Entity<User>()
.Navigation(u => u.Session)
.AutoInclude();
modelBuilder.Entity<User>()
.Navigation(u => u.UserData)
.AutoInclude();
}
public bool GetUserByCondition(System.Linq.Expressions.Expression<Func<User, bool>> predicate, out User? user)
{
user = Users.FirstOrDefault(predicate);
if (user == null)
{
return false;
}
Log.LogToDB($"UserData is null: {user.UserData == null}");
Log.LogToDB($"Session is null: {user.Session == null}");
Log.LogToDB($"User ID: {user.UserID}");
// TODO: Figure out why eager loading isn't working
Entry(user).Reference(u => u.Session).Load();
Log.LogToDB($"Session ID: {user.Session.SessionID}");
Entry(user).Reference(u => u.UserData).Load();
Log.LogToDB($"UserData ID: {user.UserData.UserDataID}");
// for some reason the context will think all of these are being added after updating them and calling .SaveChanges(). Manually attach them to fix this
Attach(user);
Attach(user.Session);
// Exception throwing because user.UserData.UserDataID = 0 / is unset
Attach(user.UserData);
return true;
}
}
public class User : IUser
{
[Key]
public long UserID { get; set; }
public UserData UserData { get; set; }
public Session Session { get; set; }
protected User() { }
public User(Context db)
{
UserData ud = new UserData(this);
UserData = ud;
db.UserDatas.Add(ud);
}
}
public class Session : ISession
{
[Key]
public long SessionID { get; set; }
public long UserID { get; set; }
public User User { get; set; }
protected Session() { }
static public Session CreateSessionForUser(User user, out string token)
{
Session session = new Session()
{
UserID = user.UserID,
User = user,
};
return session;
}
}
static public class SessionHelper
{
static public void CreateNewSessionForUser(Context db, User user)
{
Session newSession = Session.CreateSessionForUser(user, out token);
db.Sessions.Add(newSession);
db.SaveChanges();
}
}
public class UserData : IUserData
{
[Key]
public long UserDataID { get; set; }
public long UserID { get; set; }
public User User { get; set; }
}
奇怪的行为发生在
GetUserByCondition
。第一个日志检查是否 user.UserData == null
将打印 false
,但第二个日志检查 user.Session == null
将打印 true
,尽管两个导航都在 AutoInclude
中指定为 OnModelCreating
。
通过
手动加载
Session
后
Entry(user).Reference(u => u.Session).Load();
打印
user.Session.SessionID
将打印正确的id。但是,尝试对 UserData
执行相同的操作,将打印 null
或 0
,具体取决于我是否将 UserDataID
切换为可为空。我已确认所有 3 个对象都在数据库中,并且所有外键/关系均已设置。
任何有关 Entity Framework Core 无法检索
UserDatas
上的主键的帮助将不胜感激
我看到你改变了你的方法,但既然我找到了它,就会分享它!
首先,我发现你的 ctor 很奇怪,但经过一些调试后发现,当 EF Core 尝试从数据库加载你的对象时,它仅加载基于你的代码的
UserData
对象。这就是为什么您在数据库中看到您的对象但没有被 EF Core 加载!
public User(Context db)
{
UserData ud = new UserData(this);
UserData = ud;
db.UserDatas.Add(ud);
}