Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/meteor/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Entity framework 编辑/更新EF Core中的集合:从DTO还是从存储库?_Entity Framework_Entity Framework Core_Automapper_.net 5_Ef Core 5.0 - Fatal编程技术网

Entity framework 编辑/更新EF Core中的集合:从DTO还是从存储库?

Entity framework 编辑/更新EF Core中的集合:从DTO还是从存储库?,entity-framework,entity-framework-core,automapper,.net-5,ef-core-5.0,Entity Framework,Entity Framework Core,Automapper,.net 5,Ef Core 5.0,我有以下几类:公司,国家,个人 class Country { public int Id { get; set; } public string Name { get; set; } public Person President { get; set; } ICollection<Company> Companies { get; set; } ICollection<Person> People { get; set; } }

我有以下几类:
公司
国家
个人

class Country
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Person President { get; set; }
    ICollection<Company> Companies { get; set; }
    ICollection<Person> People { get; set; }
}
class Company 
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Code { get; set; }
    public Country Country { get; set; }
    ICollection<Person> People { get; set; }
}
class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}
我用AutoMapper,我也用

CreateMap<Company, CompanyDTO>()
    .ForMember(p => p.CountryName, o => o.MapFrom(p => p.Country.Name))
    .ForMember(p => p.PeopleIds, o => o.MapFrom(p => p.People.Select(s => s.Id).ToArray()))
    .ForMember(p => p.PeopleNames, o => o.MapFrom(p => p.People.Select(s => s.Name).ToArray()))
    .ReverseMap();
从存储库

对于问题的第一部分,Automapper有一个
Map
调用,可以将值复制到现有实体

var company = await _repository.SingleAsync(spec);
mapper.Map(companyDto, company);
ReverseMap
应该注意将细节返回到实体中,尽管它不会执行添加/删除关联实体之类的操作。因此,要添加/删除的ID的实现与我使用的方法一致


当涉及到更新数据和关联时,通常建议尽可能原子化地拆分操作;例如,让操作添加或删除国家/地区关联,而不是让客户端更改整个公司对象图,然后通过类似“UpdateCompany”的方法提交更改。“全部”或“一个”更新操作可能涉及相当多的工作,因此我会将其保留在绝对需要的位置。

在Steve的建议之后,我构建了一个扩展方法,可以将存储库中的任何现有集合更新为一组ID:

public static class BusinessExtensions
{
    /// <summary>
    /// Updates a business objects collection (usually from repository) 
    /// to correspond to the given list of ID's (usually updated in the View)
    /// </summary>
    /// <typeparam name="T">Any entity having an Id (IdEntity)</typeparam>
    /// <param name="collectionToUpdate">reposotory collection to be updated</param>
    /// <param name="updatedIds">list of new id's to syncronise with the repository collection</param>
    /// <param name="Spec">function transforming a list of ids into a list of business objects from repository</param>
    public static void SyncCollection<T>(this ICollection<T> collectionToUpdate, int[] updatedIds, Func<int[], IEnumerable<T>> Spec)
        where T : IdEntity
    {
        var existingEntityIds = collectionToUpdate.Select(x => x.Id).ToList();
        var entityIdsToRemove = existingEntityIds.Except(updatedIds).ToArray();
        var entityIdsToAdd = updatedIds.Except(existingEntityIds).ToArray();
        var entitiesToRemove = Spec(entityIdsToRemove);
        var entitiesToAdd = Spec(entityIdsToAdd);

        foreach (var entity in entitiesToRemove)
            collectionToUpdate.Remove(entity);
        foreach (var entity in entitiesToAdd)
            collectionToUpdate.Add(entity);
    }
}

什么存储库?DbContext已经是一个工作单元,DbSet已经是一个存储库。问题的其余部分也不清楚-您可以使用AutoMapper从API DTO映射到数据库DTO。您不局限于只映射一种方式。如果要基于API DTO更新或创建新的数据库行,请将DTO映射到EF实体并持久化它们。如果适当地使用POST和PUT方法,您将知道DTO是用于新对象还是用于更新对象。如果没有,您应该有不同的创建/更新操作。我有两个可以从中创建业务对象的源:从(DbContext==Repository==数据库),使用Repository对象,或者从视图(=从DTO,使用mapper对象),我将
国家
对象保存在DB中我为这个问题添加了一个扩展方法作为“答案”,如果您使用
标识
类似对象,可能会很有用…我现在还没有使用的地图(源、目的地)!我会测试它!谢谢!是的,虽然Automapper的文档通常非常有用,但有关特定方法的详细信息可能有点隐藏。我试图找到
地图的官方文档链接,但找不到链接到答案的链接!:)
var company = await _repository.SingleAsync(spec);
mapper.Map(companyDto, company);
public static class BusinessExtensions
{
    /// <summary>
    /// Updates a business objects collection (usually from repository) 
    /// to correspond to the given list of ID's (usually updated in the View)
    /// </summary>
    /// <typeparam name="T">Any entity having an Id (IdEntity)</typeparam>
    /// <param name="collectionToUpdate">reposotory collection to be updated</param>
    /// <param name="updatedIds">list of new id's to syncronise with the repository collection</param>
    /// <param name="Spec">function transforming a list of ids into a list of business objects from repository</param>
    public static void SyncCollection<T>(this ICollection<T> collectionToUpdate, int[] updatedIds, Func<int[], IEnumerable<T>> Spec)
        where T : IdEntity
    {
        var existingEntityIds = collectionToUpdate.Select(x => x.Id).ToList();
        var entityIdsToRemove = existingEntityIds.Except(updatedIds).ToArray();
        var entityIdsToAdd = updatedIds.Except(existingEntityIds).ToArray();
        var entitiesToRemove = Spec(entityIdsToRemove);
        var entitiesToAdd = Spec(entityIdsToAdd);

        foreach (var entity in entitiesToRemove)
            collectionToUpdate.Remove(entity);
        foreach (var entity in entitiesToAdd)
            collectionToUpdate.Add(entity);
    }
}
var spec = new CompanyWithPeopleSpecification(id);
var company = await _repository.SingleOrDefaultAsync(spec);

_mapper.Map(comapnyDto, company;

company.People.SyncCollection(companyDto.PeopleIds, 
    ids => _repository.List(new PeopleFromIdsSpecification(ids)));