【问题标题】:Linq mystery error in EF queryEF 查询中的 Linq 神秘错误
【发布时间】:2017-06-05 23:33:45
【问题描述】:

我有一个 UserProfile 类

 [Key]
    public int UserProfileId { get; set; }

    public string AppUserId { get; set; }

   ...code removed for brevity

    [Required]
    public NotificationMethod NotificationMethod { get; set; }

    public List<PrivateMessage> PrivateMessages { get; set; }

    public List<Machine> OwnedMachines { get; set; }

    public bool IsProfileComplete { get; set; }

    public byte[] Avatar { get; set; }
    public string AvatarUrl { get; set; }       

    public string GetFullName()
    {
        return $"{FirstName} {LastName}";
    }
}

我也有一个 PrivateMessage 类

 public class PrivateMessage
{
    [Key]
    public int Id { get; set; }

    public int MessageToUserId { get; set; }

    public int MessageFromUserId { get; set; }

    public DateTime DateSent { get; set; }
    public string Message { get; set; }
}

我设置了一个简单的测试来提取包含各种内容的用户配置文件。 PrivateMessages 总是出错。这是一个出错的示例方法。

public static UserProfile GetUserProfileIncluding(string appUserId)
    {
        using (RestorationContext)
        {
            //RestorationContext.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);

            return RestorationContext.MemberProfiles.Where(m => m.AppUserId == appUserId)
                  .Include(m=> m.PrivateMessages)
                  .FirstOrDefault();
        }
    }

指出的错误是

InnerException {"无效的列名'UserProfile_UserProfileId'。\r\n无效的列名'UserProfile_UserProfileId'。"} System.Exception {System.Data.SqlClient.SqlException}

我不明白,两个表都没有列“UserProfile_UserProfileId”

如果我使用属性 O​​wnedMachines 而不是 PrivateMessages,它工作得非常好(当然不是,当有 6 条匹配时它只提取 4 条记录,但我稍后会弄清楚)。

public static UserProfile GetUserProfileIncluding(string appUserId)
    {
        using (RestorationContext)
        {

            return RestorationContext.MemberProfiles.Where(m => m.AppUserId == appUserId)
                  .Include(m=> m.OwnedMachines)
                  .FirstOrDefault();
        }
    }

您可以在下面看到,Machine 的设置与 PrivateMessage 完全相同,尽管它有两个 UserProfile 而不是一个

public class Machine
{
    [Key]
    public int MachineId { get; set; }

    public int OwnerProfileId { get; set; }

    public int SerialNumber { get; set; }

    public string YearofManufacture { get; set; }

    public string ModelName { get; set; }

    public Manufacturer Manufacturer { get; set; }      

    public DateTime DateAcquired { get; set; }
}

我现在在这方面花了很多时间。这是否与我在 PrivateMessage 中有两个 UserProfile Id int 属性的事实有关? (MessageToUserId 和 MessageFromUserId)。我最初将这些设置为带有 UserProfile 属性的外键,就像这样

    [ForeignKey("MessageToProfile")]
    public int MessageToUserId { get; set; }

    public UserProfile MessageToProfile { get; set; }

    [ForeignKey("MessageFromProfile")]
    public int MessageFromUserId { get; set; }

    public UserProfile MessageFromProfile { get; set; }

但我认为它们可能是错误的根源,但我删除了它们,但显然不是。

更新: 经过多次反复试验,很明显当前方法总是会出错,因为该方法正在寻找一个不存在的可导航属性。由于我在 PrivateMessage 中有两个 int 属性,因此当尝试将它们包含在 UserProfile 对象中时,我需要通过 MessageToUserId 进行过滤,然后将它们包含在内。不知道如何过滤和包含。

使用这个方法应该可以的;

public static UserProfile GetProfileForLoggedInUser(string appUserId)
    {

        using (RestorationContext)
        {
            RestorationContext.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);

            var profile= RestorationContext.MemberProfiles.Include(m => m.OwnedMachines)
                                           .FirstOrDefault(m => m.AppUserId == appUserId);
            var pms = RestorationContext.PrivateMessages.Where(m => m.MessageToUserId == profile.UserProfileId).ToList();

            if (profile != null) profile.PrivateMessages = pms;

            return profile;
        }
    }

但它给出了相同的无效列错误 UserProfile_UserProfileID。

这里是 TSql

SELECT 
[Extent1].[Id] AS [Id], 
[Extent1].[MessageToUserId] AS [MessageToUserId], 
[Extent1].[MessageFromUserId] AS [MessageFromUserId], 
[Extent1].[DateSent] AS [DateSent], 
[Extent1].[Message] AS [Message], 
[Extent1].[UserProfile_UserProfileId] AS [UserProfile_UserProfileId]
FROM [RestorationContext].[PrivateMessages] AS [Extent1]
WHERE [Extent1].[MessageToUserId] = @p__linq__0

由于这只是查询 PrivateMessage 表,它为什么要查找该 UserProfileId,它与该表无关。以下是 SSMS 中的表属性

那个 UserProfileID 废话是从哪里来的?

【问题讨论】:

    标签: c# entity-framework linq


    【解决方案1】:

    您的 Machine 包含有效,因为 Machine 类只有一个外键 UserProfile

    PrivateMessage 类中的同一张表有 2 个外键,当然,UserProfile 类中需要 2 个 ICollection 导航属性。 EntityFramework 不知道在 PrivateMessage 类中使用哪个外键来加载 UserProfile 类中的 ICollection&lt;PrivateMessage&gt; 属性。

    public ICollection<PrivateMessage> FromPrivateMessages { get; set; }
    public ICollection<PrivateMessage> ToPrivateMessages { get; set; }
    

    在你的上下文类中

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<PrivateMessage>()
                    .HasRequired(m => m.MessageFromProfile)
                    .WithMany(t => t.FromPrivateMessages)
                    .HasForeignKey(m => m.MessageFromUserId)
                    .WillCascadeOnDelete(false);
    
        modelBuilder.Entity<PrivateMessage>()
                    .HasRequired(m => m.MessageToProfile)
                    .WithMany(t => t.ToPrivateMessages)
                    .HasForeignKey(m => m.MessageToUserId)
                    .WillCascadeOnDelete(false);
    }
    

    更新

    EF 使用约定优于配置,并且通过在 PrivateMessage 类中具有 UserProfile 的导航属性将暗示关系,EF 将尝试以 &lt;Navigation Property Name&gt;_&lt;Primary Key Name of Navigation Property type&gt; 的形式查找外键,从而为您提供 @987654335 @。

    此时您应该想知道为什么UserProfile_UserProfileId 而不是UserProfile_MessageToUserIdUserProfile_MessageFromUserId。这是因为你的外键属性告诉 EF 在你的 UserProfile 类中使用 UserProfileId 属性。

    你现在可以做的是,像这样去掉外键属性

    public int MessageToUserId { get; set; }
    
    public UserProfile MessageToProfile { get; set; }
    
    public int MessageFromUserId { get; set; }
    
    public UserProfile MessageFromProfile {get; set; }
    

    并添加另一个ICollection 并像我在更新之前所说的那样进行模型构建器配置。

    【讨论】:

    • @IvanJazz...我知道这是问题所在,这就是我删除导航属性的原因。我只想要 PrivateMessage 类中的两个 int 属性。然后我可以将它们用作过滤器参数来获取个人配置文件。我猜我需要对 include 参数进行过滤,因为没有导航属性,正常的 lambda 表达式将无法工作。
    • @dinotom 您可以从PrivateMessage 中删除导航属性,但您仍然需要UserProfile 类中的2 个集合导航属性(如答案中所述)和正确 关系配置(在没有导航属性的情况下应该写的稍有不同)。如果您保留单个未配置的集合,EF 会将其视为第三个关系(无反向导航属性),并且按照惯例将尝试将其映射到 UserProfile_UserProfileId FK 列。
    猜你喜欢
    • 1970-01-01
    • 2015-03-13
    • 2017-04-20
    • 2014-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多