How to expose part of Entity as DataContract?

2020-04-12 09:16发布

Up to now, when working with WCF, I have always been exposing the whole either EF generated entities, or POCOs(by modifying the T4 template to include DataContract and DataMember on POCOs and properties) as DataContract.

Now, I have come across a situation that I cannot expose the whole thing, and need to explicitly specify my DataContract to be a subset of the entities.

It worth saying that one of my entities is something like below:

enter image description here

And I want to just expose Id, Name, CategoryId, Price.

Insert/Update of rest of the fields (ActiveFrom, InactiveDate, Supported) is something that will be decided based on the BR, and client doesn’t know , and should not know indeed, anything about them.

I have tried following approaches, but each of them seems to have problem/not working:

  1. Using AutoMapper : I need to map a source object to a destination object, and this is a one way mapping, so for presentation purposes I can map Product to ProductContract. But for adding/updating the product, it does not work as it cannot do a two way mapping.

  2. Use the reflection and create a metadata class for the entities and add the [DataMember] attribute to the properties of the Metadata class as below (please note that I haven’t included the unwanted fields):

    public class ProductMD : AssociatedMetadataTypeTypeDescriptionProvider
        {
            public ProductMD() :
                base(typeof(Product))
            {
            }
            [DataMember]
            public int Id{ get; set; }
    
            [DataMember]
            public string Name { get; set; }
    
            [DataMember]
            public int? CategoryID { get; set; }
    
            [DataMember]
            public decimal? Price { get; set; }
        }
    

    And then use the ProductMD as an attribute for the Product partial class without touching the auto-generated entity (FYI: I have changed the POCO T4 template generator to include the [DataContract] on each entity):

    [MetadataType(typeof(ProductMD))]
    public partial class Product
    {  
    }
    

    But on the client side, I do not have access to any of the DataMembers of the Product.

Now my question is that, what is the best approach to gain what I want to do (exposing a subset of the entities as DataContract)?

2条回答
太酷不给撩
2楼-- · 2020-04-12 09:19

First of all you should never expose the whole entity as a data contract, as it is a domain object, not the data transfer object. Not just in that particular situation. Never. Now you're creating a confusing inconsistency between entities which do have a DTO and those which don't.

Returning to a question: AutoMapper seems to be pretty ok. You just have to define 2 mappings. And probably Ignore() missing properties when mapping back to entity.

查看更多
走好不送
3楼-- · 2020-04-12 09:30

I would go with option 1 -> AutoMapper.

it does not work as it cannot do a two way mapping.

You could define two way mapping:

Mapper.CreateMap<Product, ProductContract>();
Mapper.CreateMap<ProductContract, Product>();

obviously if in your ProductContract you have less properties than in your domain model when doing the mapping, only the corresponding properties will be populated.

When doing the inverse map for updating you could do the following:

ProductContract pc = ...
Product productToUpdate = GetProduct(pc.Id);
Mapper.Map<ProductContract, Product>(pc, product);
// at this stage the product model will have the properties that
// were present in the ProductContract being mapped from them and
// the rest of the properties will stay unmodified, i.e. they will
// have their initial values that were retrieved from the database.
// Now we can update the product:
UpdateProduct(product);
查看更多
登录 后发表回答