简体   繁体   中英

From entity to DTO (retrieving information that are only on DB)

I have domain class (says EventoSottomissione ) with some informations. Then I've DTO (says EventoSottomissioneDTO ) with the same informatiosn and something related to persistence (ie both EventoSottomissione and EventoSottomissioneDTO has EventCode property, but only EventoSottomissioneDTO has IdEvent property).

Now suppose I have a method Delete that will remove some events from the database. This method is called from my domain layer and so, this is ignorant about persistence layer and DTO, thus Delete will take an IEnumerable of EventoSottomissione . DbSet indeed have to take a IEnumerable of EventoSottomissioneDTO .

So, the first thing to do in method Delete is to "convert" the IEnumerable<EventoSottomissione> in IEnumerable<EventoSottomissioneDTO > but I can't do this simply using AutoMapper (for instance: how to fill IdEvent properties - this information is only on the DB)

So my Delete method is something like that:

public bool Delete(IEnumerable<T> entities) // typeof(T) is EventoSottomissione
{
    // get all eventCode from entities collection
    var listOfCodes = (from p in entities.Cast<EventoSottomissione>().ToList<EventoSottomissione>()
                     select p.EventCode).Distinct();

    // using the list of eventCode I can create list  EventoSottomissioneDTO (with even IdEvent)
    IEnumerable<EventoSottomissioneDTO> listOfDto = (from _db in Context.CatalogoEventi
                                            where listOfCodes.Contains(_db.EventCode)
                                            select _db).ToList<EventoSottomissioneDTO>();
    DbSet.RemoveRange(listOfDto);      
    return Context.SaveChanges() > 0;
}

This do the job, but I find this solution really scary. How can I do everything in a more elegant manner?

First of all, how DTOs are related to EF layer (persistence)? DTOs are usually projection of domain entities, to make them more "serializable" and to remove "noise" related to persistence layer (eg navigation properties, which can cause cyclic serialization problem), properties that should not exposed by security or other application logic, etc.).
To answer your question we have to understand what is the income parameters for removing? From your code I've made assumption that you are removing all the entities that has EventCode that is actually in listOfCodes .
Just imagine someone who uses your current API: what properties should be populated in objects of type T? What type T actually is? Will properties that are not related to PK ( IdEvent I think) be used in delete filtering logic? What does returned bool mean? Does it mean that everything was deleted or just something? It can break any brain, right?
So do you want to delete by IdEvent or do you want to stick to the current logic and delete all the entities that has EventCode that appears in listOfCodes ? If you want to delete by EventCode then of course if you don't use any EntityFramework.Extended you'll have to get all the entities by listOfCodes and then remove all those entities like you have already done. Just pass in more appropriate parameter, something like IEnumerable<EventCodeType> eventCodes , because current generic IEnumerable<T> entities doesn't make any sense for anyone who will use your API. Also I'd change method name to something like DeleteByEventCodes .
Or you can use EntityFramework.Extended and delete needed entities using .Delete(expression) . But don't call .SaveChanges() because this library makes call JIT when you call the .Delete(expression) , that's why I don't like it too much, because it breaks some of EF design concepts.
So main idea is to redesign your current API: change method name and incoming parameter to more suitable one. Then your code will be much easier to understand and to use.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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