繁体   English   中英

EF查询中的Linq神秘错误

[英]Linq mystery error in EF query

我有一个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”列

如果我使用属性OwnedMachines而不是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完全相同,尽管它具有两个UserProfiles而不是一个

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废话来自哪里?

该UserProfileID废话来自哪里?

因为Machine类只有一个UserProfile外键,所以您的Machine包含项起作用。

PrivateMessage类中,您有2个外键指向同一个表,因此,在UserProfile类中自然需要2个ICollection导航属性。 EntityFramework不知道在PrivateMessage类中使用哪个外键来加载UserProfile类中的ICollection<PrivateMessage>属性。

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);
}

UPDATE

EF使用约定而不是配置,并且通过在PrivateMessage类中具有UserProfile导航属性将暗示关系,并且EF会尝试以<Navigation Property Name>_<Primary Key Name of Navigation Property type>的形式查找外键,这给你UserProfile_UserProfileId

您应该想知道为什么此时要使用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并按照我在更新前所述的方式进行modelBuilder配置。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM