相关实体返回Null

问题描述 投票:0回答:2

我正在使用EF core 2.1.14这是我通过脚手架创建的DbContext类:

public partial class AgriDbContext : DbContext
{
    public AgriDbContext()
    {
    }

    public AgriDbContext(string connectionString)
        : base(GetOptions(connectionString))
    {
    }
    private static DbContextOptions GetOptions(string connectionString)
    {
        return SqlServerDbContextOptionsExtensions.UseSqlServer(new DbContextOptionsBuilder(), connectionString).Options;
    }
    public virtual DbSet<Advertisement> Advertisements { get; set; }
    public virtual DbSet<AgroItem> AgroItems { get; set; }
    public virtual DbSet<BuyerAddsDifferentAdsToFav> BuyerAddsDifferentAdsToFavs { get; set; }
    public virtual DbSet<BuyersAddAgroItemToInterest> BuyersAddAgroItemToInterests { get; set; }
    public virtual DbSet<Category> Categories { get; set; }
    public virtual DbSet<City> Cities { get; set; }
    public virtual DbSet<SellersFavoritesBuyer> SellersFavoritesBuyers { get; set; }
    public virtual DbSet<User> Users { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.HasAnnotation("ProductVersion", "2.2.0-rtm-35687");

        modelBuilder.Entity<Advertisement>(entity =>
        {
            entity.Property(e => e.Picture).IsUnicode(false);

            entity.HasOne(d => d.City)
                .WithMany(p => p.Advertisements)
                .HasForeignKey(d => d.CityId)
                .OnDelete(DeleteBehavior.ClientSetNull)
                .HasConstraintName("ADVERTISEMENTS_INCLUDE_A_CITY");

            entity.HasOne(d => d.Item)
                .WithMany(p => p.Advertisements)
                .HasForeignKey(d => d.ItemId)
                .HasConstraintName("AN_ADVERTISEMENT_IS_RELATED_TO_AN_ITEM");

            entity.HasOne(d => d.Seller)
                .WithMany(p => p.Advertisements)
                .HasForeignKey(d => d.SellerId)
                .HasConstraintName("USERS_POST_ADVERTISEMENTS");
        });

        modelBuilder.Entity<AgroItem>(entity =>
        {
            entity.Property(e => e.Name).IsUnicode(false);

            entity.Property(e => e.Uname).IsUnicode(false);

            entity.HasOne(d => d.Category)
                .WithMany(p => p.AgroItems)
                .HasForeignKey(d => d.CategoryId)
                .OnDelete(DeleteBehavior.ClientSetNull)
                .HasConstraintName("AGRO_ITEMS_BELONG_TO_A_CATEGORY");
        });

        modelBuilder.Entity<BuyerAddsDifferentAdsToFav>(entity =>
        {
            entity.HasKey(e => new { e.BuyerId, e.AdId });

            entity.HasOne(d => d.Ad)
                .WithMany(p => p.BuyerAddsDifferentAdsToFavs)
                .HasForeignKey(d => d.AdId)
                .OnDelete(DeleteBehavior.ClientSetNull)
                .HasConstraintName("FK_BUYER_ADDS_DIFFERENT_ADS_TO_FAV_ADVERTISEMENTS");

            entity.HasOne(d => d.Buyer)
                .WithMany(p => p.BuyerAddsDifferentAdsToFavs)
                .HasForeignKey(d => d.BuyerId)
                .HasConstraintName("FK_BUYER_ADDS_DIFFERENT_ADS_TO_FAV_USERS");
        });

        modelBuilder.Entity<BuyersAddAgroItemToInterest>(entity =>
        {
            entity.HasKey(e => new { e.BuyerId, e.ItemId });

            entity.HasOne(d => d.Buyer)
                .WithMany(p => p.BuyersAddAgroItemToInterests)
                .HasForeignKey(d => d.BuyerId)
                .OnDelete(DeleteBehavior.ClientSetNull)
                .HasConstraintName("FK_BUYERS_ADD_AGRO_ITEM_TO_INTEREST_USERS");

            entity.HasOne(d => d.Item)
                .WithMany(p => p.BuyersAddAgroItemToInterests)
                .HasForeignKey(d => d.ItemId)
                .OnDelete(DeleteBehavior.ClientSetNull)
                .HasConstraintName("FK_BUYERS_ADD_AGRO_ITEM_TO_INTEREST_AGRO_ITEMS");
        });

        modelBuilder.Entity<Category>(entity =>
        {
            entity.Property(e => e.Name).IsUnicode(false);

            entity.Property(e => e.Uname).IsUnicode(false);
        });

        modelBuilder.Entity<City>(entity =>
        {
            entity.HasIndex(e => e.Id)
                .HasName("UNIQUE_LOCATION")
                .IsUnique();

            entity.Property(e => e.Name).IsUnicode(false);
        });

        modelBuilder.Entity<SellersFavoritesBuyer>(entity =>
        {
            entity.HasKey(e => new { e.SellerId, e.BuyerId });

            entity.HasOne(d => d.Buyer)
                .WithMany(p => p.SellersFavoritesBuyerBuyers)
                .HasForeignKey(d => d.BuyerId)
                .HasConstraintName("FK_SELLERS_FAVORITES_BUYERS_USERS1");

            entity.HasOne(d => d.Seller)
                .WithMany(p => p.SellersFavoritesBuyerSellers)
                .HasForeignKey(d => d.SellerId)
                .OnDelete(DeleteBehavior.ClientSetNull)
                .HasConstraintName("FK_SELLERS_FAVORITES_BUYERS_USERS");
        });

        modelBuilder.Entity<User>(entity =>
        {
            entity.HasIndex(e => new { e.CcompanyCode, e.CcountryCode, e.Cphone })
                .HasName("UNIQUE_CONTACT")
                .IsUnique();

            entity.Property(e => e.Address).IsUnicode(false);

            entity.Property(e => e.Fname).IsUnicode(false);

            entity.Property(e => e.Lname).IsUnicode(false);

            entity.HasOne(d => d.City)
                .WithMany(p => p.Users)
                .HasForeignKey(d => d.CityId)
                .OnDelete(DeleteBehavior.ClientSetNull)
                .HasConstraintName("FK_USERS_CITIES");
        });

        OnModelCreatingPartial(modelBuilder);
    }

    partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}

在上面的代码中,CityId与外键正确相关,并且在User类中还有City的属性。但是,每当我有一个用户时,它都会在City属性中返回null,但会从数据库中返回CityId。

下面是我的实体模型类

[Table("USERS")]
public partial class User
{
    public User()
    {
        Advertisements = new HashSet<Advertisement>();
        BuyerAddsDifferentAdsToFavs = new HashSet<BuyerAddsDifferentAdsToFav>();
        BuyersAddAgroItemToInterests = new HashSet<BuyersAddAgroItemToInterest>();
        SellersFavoritesBuyerBuyers = new HashSet<SellersFavoritesBuyer>();
        SellersFavoritesBuyerSellers = new HashSet<SellersFavoritesBuyer>();
    }

    public long Id { get; set; }
    [Required]
    [Column("FName")]
    public string Fname { get; set; }
    [Required]
    [Column("LName")]
    public string Lname { get; set; }
    [Required]
    [Column("CCompanyCode")]
    [StringLength(3)]
    public string CcompanyCode { get; set; }
    [Required]
    [Column("CCountryCode")]
    [StringLength(3)]
    public string CcountryCode { get; set; }
    [Required]
    [Column("CPhone")]
    [StringLength(7)]
    public string Cphone { get; set; }
    [Required]
    public string Address { get; set; }
    [Column("GLat", TypeName = "decimal(10, 8)")]
    public decimal? Glat { get; set; }
    [Column("GLng", TypeName = "decimal(11, 8)")]
    public decimal? Glng { get; set; }
    public bool BuyerFlag { get; set; }
    public bool SellerFlag { get; set; }
    public short CityId { get; set; }

    [ForeignKey("CityId")]
    [InverseProperty("Users")]
    public virtual City City { get; set; }
    [InverseProperty("Seller")]
    public virtual ICollection<Advertisement> Advertisements { get; set; }
    [InverseProperty("Buyer")]
    public virtual ICollection<BuyerAddsDifferentAdsToFav> BuyerAddsDifferentAdsToFavs { get; set; }
    [InverseProperty("Buyer")]
    public virtual ICollection<BuyersAddAgroItemToInterest> BuyersAddAgroItemToInterests { get; set; }
    [InverseProperty("Buyer")]
    public virtual ICollection<SellersFavoritesBuyer> SellersFavoritesBuyerBuyers { get; set; }
    [InverseProperty("Seller")]
    public virtual ICollection<SellersFavoritesBuyer> SellersFavoritesBuyerSellers { get; set; }
}

我正在使用这种存储库方法来获取用户

public EFarmer.Models.User GetUser(ContactNumberFormat contact)
{
    var user = users
        .Where(x => x.CcountryCode == contact.CountryCode
        && x.CcompanyCode == contact.CompanyCode
        && x.Cphone == contact.PhoneNumber).First() ?? null;
    return (user != null) ? new EFarmer.Models.User
    {
        Address = user.Address,
        City = EFarmer.Models.City.Convert(user.City),
        ContactNumber = new ContactNumberFormat(user.CcountryCode, user.CcompanyCode, user.Cphone),
        IsBuyer = user.BuyerFlag,
        IsSeller = user.SellerFlag,
        Location = new GeoLocation { Latitude = user.Glat, Longitude = user.Glng },
        Name = new NameFormat { FirstName = user.Fname, LastName = user.Lname },
        Id = user.Id
    } : null;
}

这是将实体模型转换为我的业务模型的转换方法,由于实体模型中City中的空值,它给出了空引用异常

public static City Convert(EFarmerPkModelLibrary.Entities.City city)
{
    return new City
    {
        GeoLocation = new GeoLocation { Latitude = city.Glat, Longitude = city.Glng },
        Id = city.Id,
        Name = city.Name
    };
}
c# asp.net entity-framework .net-core ef-core-2.1
2个回答
0
投票

从您的示例和标签(EF Core 2.1)中可以看到,问题可能是尚未启用延迟加载。检查是否已添加EF Core Proxies的依赖项,并将optionsBuilder.UseLazyLoadingProxies();添加到DbContext OnModelConfiguring替代中。

不过,建议不要滚动自己的映射器,例如静态Convert方法,而要利用现有的映射器,例如AutoMapper。与EF集成的Automapper的关键功能是投影(ProjectTo)。这可以将您的DTO / ViewModels构建为馈入数据库的Linq表达式的一部分,从而导致查询效率大大提高,并且不会出现诸如延迟加载之类的多次点击。

[使用延迟加载时,您将有1个查询命中来从用户中获取所有字段,然后将有1个查询命中来获取您所在城市的所有字段,再加上1个命中,则每个其他延迟加载调用都将得到。如果您正在执行获取用户列表之类的操作,则将获得1次点击才能获得用户列表,但是每个城市的每个用户都会获得1次点击!

急切加载,您将有1个查询命中,以从您的用户及其相关城市中获取所有字段,这是性能较低的命中。但是,无论您的DTO / ViewModel是否需要它们,它仍在获取all字段。还存在忘记显式渴望查询中与负载相关的数据的风​​险,尤其是在扩展实体以添加新关系时,这最终会导致延迟加载性能损失或问题。

使用Automapper的ProjectTo,您将有1次查询命中,仅从User,City和DTO / ViewModel请求的任何其他相关实体中获取字段。无需记住与Include亲戚在一起的时间,也不必担心懒惰的打击。干净,高效且面向未来。


0
投票

这是有关Entity Framework如何管理延迟加载的全部内容。此答案List returned by Entity Framework is null

中已经解决了相似的主题
© www.soinside.com 2019 - 2024. All rights reserved.