我是第一次使用ASP.NET Core,我正在try 创建一个API.我有一个问题,当我试图返回一个城市的用户使用懒惰加载代理程序包.有谁能帮帮我吗?谢谢你的帮助.

这是我的dbcontext配置

services.AddDbContext<ApplicationDbContext>(option =>
        {
            option.UseLazyLoadingProxies()                
            .UseSqlServer(configuration.GetConnectionString("DefaultConnection"));
            option.LogTo(Console.WriteLine,LogLevel.Information);
            option.EnableSensitiveDataLogging();                                
        });
        

这是我的User个实体:

using ecommerce.Domain.Abstract;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using tables.Base.Entity;

namespace ecommerce.Domain.Entities
{
    public class User : BaseEntity
    {
        public Guid Id { get; set; }

        public Guid CityId { get; set; }
        public virtual City City { get; set; }

        public string Name { get; set; }
         
        [Range(0,Double.MaxValue)]
        public int Point { get; set; }

        public Guid AccountId { get; set; } 
        public virtual Account Account { get; set; }
        
        public bool IsBlocked { get; set; }
    }
}

这是我对City实体的配置:

using ecommerce.Domain.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ecommerce.infrutructure.Configuration
{
    internal class CityConfigration : IEntityTypeConfiguration<City>
    {
        public void Configure(EntityTypeBuilder<City> builder)
        {
            builder.Property(c => c.Delivery_Price).HasDefaultValue(0);
            builder.Property(c=>c.status).HasDefaultValue(false);
            builder.HasMany(c => c.Users)
                   .WithOne(u => u.City);
        }
    }
}

在这里,user.city在返回中为空

public async Task<OperationResultBase<UserWithToken>> Handle(AddUserCommand request, CancellationToken cancellationToken)
{
    var Account = mapper.Map<Account>(request);
    var Accountresult = await this.userManager.CreateAsync(Account, request.Password);
    this.DbContext.SaveChanges();

    if (!Accountresult.Succeeded)
    {
        throw new CanotCreateAccountException(Accountresult.Errors);
    }

    var User = mapper.Map<User>(request, opts => opts.AfterMap((src, desc) => desc.AccountId = Account.Id));            

    this.DbContext.Users.Add(User);
    this.DbContext.SaveChanges();

    TokenDto TokenInfo = jwtRepository.GetTokens(Account);
    UserWithToken result = new UserWithToken()
        {
            Id = User.Id,
            Name = User.Name,
            UserName = User.Account.UserName,
            City = User.City,
            Email = User.Account.Email,
            IsBlocked = User.IsBlocked,
            Point = User.Point,   
            TokenInfo = TokenInfo
        };

    return Created<UserWithToken>(result, "The user was created successfully");
}

推荐答案

当您使用如下代码时:

var User = mapper.Map<User>(request, opts => opts.AfterMap((src, desc) => desc.AccountId = Account.Id));            

映射器实质上将运行:

var user = new User();

...它构造了一个具体的用户类.延迟加载依赖于代理来知道何时需要加载相关实体,而不是恰好为#NULL.如果您的映射只是设置User.CityID,那么没有设置City引用,并且使用"user"的以下代码没有准备好延迟加载任何尚未关联的内容.DbSet<T>.Add()返回代理:var addedUser = DbContext.Users.Add(User);

编辑:哇,那是一个头脑模糊的时刻,这是返回的更改跟踪包装,而不是实体.问题仍然是一样的,当您仅使用具体类并设置FK时,EF没有通常用于启用延迟加载的代理.使用Microsoft.EntityFrameworkCore.Proxies时,可以使用DbSet<T>.CreateProxy()方法实例化新实体,更正后的代码示例如下:

var user = DbContext.Users.CreateProxy();

mapper.Map(request, user, opts => opts.AfterMap((src, desc) => desc.AccountId = Account.Id));            

这使用了Automapper的Map(src, dest)变体,该变体用于将值复制到我们构造为延迟加载代理的现有目的地实例.我正在测试映射器是否可以被告知使用CreateProxy构造实例,但没有发现任何确凿的结果.

不过,请看一下您的代码,因为您正在创建帐户,如果结果中返回了新的帐户实体,您应该能够设置该引用:

mapper.Map(request, user, opts => opts.AfterMap((src, desc) => 
{
    desc.AccountId = Account.Id;
    desc.Account = Account
}));            

假设两个服务都使用相同的注入DbContext实例.如果不是,请不要这样做,因为这会导致帐户被视为新的、未跟踪的实体,从而导致插入重复数据或违反帐户主键的约束.

值得一提的是,在返回DTO/ViewModel时,应避免将它们与实体混合在一起.例如,返回User.City,这是一个City实体,您应该考虑只从City实体返回所需的字段,或者将City投影到DTO.混合对实体的引用可能会导致串行化程序等"接触"导航属性的问题,从而导致性能问题和循环引用.

因此,填充结果DTO的代码如下:

        City = User.City,

应该是这样的:

        City = User.City.Name,

或投影到CityDTO等,而不是传递City实体.

Asp.net相关问答推荐

Visual Studio发布的网站得到错误类型JObject is not defined when page is load on server"''"

如何处理当前文件中基本文件中的S onClick方法

如何在 ASP.NET 全球化中配置不变文化?

asp.net、url 重写模块和 web.config

指定的 CGI 应用程序遇到错误,服务器终止了进程

使用 C# 和 ASP.NET 从 Gmail/Hotmail/Yahoo 导入通讯簿

Window.Open 使用 PDF 流而不是 PDF 位置

在 ASP.NET 中更改错误消息的语言

即使使用正确的 Accepts 标头,WebAPI 也不会返回 XML

解析器错误消息:无法加载类型sometype

使用 JavaScript 更改 ASP.NET 标签的可见性

如何使用文件上传控件 Select 多个文件?

Web Api 请求内容在操作过滤器中为空

.Net Standard 2.0 类库是否有通用配置文件?

带有完整内存错误的 WCF 服务(内存门判断失败,因为可用内存) - 如何解决

使下拉列表项不可 Select

DropDownList AppendDataBoundItems(第一项为空白且无重复项)

HttpResponse.End 或 HttpResponse.Close 与 HttpResponse.SuppressContent

VS2017 无法加载文件或程序集 Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll 或其依赖项之一

Web API 必填参数