【问题标题】:Resolve DTO type into Domain type in WCF service在 WCF 服务中将 DTO 类型解析为 Domain 类型
【发布时间】:2015-07-23 06:56:27
【问题描述】:

我有一个 WCF 服务,它通过 net.tcp 通过 EntityFramework 与 SQL 一起工作

允许客户端通过 Id 从 Db 中查询项目。

我有很多这样的方法:

    public SiteDTO GetSiteById(long siteId)
    {
        using (var context = new MyDbContext())
        {
            var site = context.Site.Find(siteId);
            return AutoMapper.Mapper.Map<SiteDTO>(site);
        }
    }

所以我决定用一种方法来统治他们:

    public TDTO GetEntityById<TDTO, TSet>(object id)
        where TDTO : class
        where TSet : class
    {
        using (var context = new MyDbContext())
        {
            var entity = context.Set<TSet>().Find(id);
            if (entity == null)
                return default(TDTO);
            return AutoMapper.Mapper.Map<TSet, TDTO>(entity);
        }
    }

但问题是应该使用它的客户端对TSet 类型一无所知(它是一种数据库类型,客户端仅适用于DTO),因此不能以这种方式调用此方法。我需要这样做:

    public TDTO GetEntityById<TDTO>(object id)
        where TDTO : class
    {
        using (var context = new MyDbContext())
        {
            //Something like this and a lot of reflection...
            Type setType = Resolver(typeof(TDTO)); 
            //I know this won't work. Just to show my intentions
            var entity = context.Set<setType>().Find(id); 
            if (entity == null)
                return default(TDTO);
            return AutoMapper.Mapper.Map<setType, TDTO>(entity);
        }
    }

我知道如何以稳健的方式解决问题 - 让 Dictionary&lt;Type,Type&gt; 注册一次并使用它。

问题: 有没有更优雅的方式(可能使用 AutoMapper 方法)来做到这一点?

【问题讨论】:

  • 我认为 GetEntityById&lt;T,P&gt; 不应该暴露给客户端,它应该是一个私有方法并由 wcf 服务调用。实体和DTO的关系比较复杂,如果客户端直接调用gernic方法,可能无法适应未来的变化

标签: c# entity-framework generics automapper parametric-namespaces


【解决方案1】:

如果您可以使用静态解析器,那么以下应该可以工作:

public static class DTOResolver
{
    public static void RegisterSetForDTO<TSet, TDTO>()
        where TDTO : class
        where TSet : class
    {
        DTOResolver<TDTO>.SetType = typeof(TSet);
        DTOResolver<TDTO>.SetMapper = new DTOResolver<TDTO>.Mapper<TSet>();
    }
}
public static class DTOResolver<TDTO> where TDTO : class
{
    public abstract class Mapper
    {
        public abstract TDTO Map(Object entity);
    }
    public class Mapper<TSet> : Mapper
    {
        public override TDTO Map(Object entity)
        {
            return AutoMapper.Mapper.Map<TSet, TDTO>((TSet) entity);
        }
    }
    public  static  Type    SetType { get; set; }
    public  static  Mapper  SetMapper { get; set; }
}

假设 DTO 和集合是这样的:

public class DTO1 {}
public class Set1 {}
public class DTO2 {}
public class Set2 {}

像这样注册您的映射:

static void Setup()
{
    DTOResolver.RegisterSetForDTO<Set1, DTO1>();
    DTOResolver.RegisterSetForDTO<Set2, DTO2>();
}

然后像这样修改你的GetEntityById

public TDTO GetEntityById<TDTO>(object id)
    where TDTO : class
{
    using (var context = new MyDbContext())
    {
        var entity = context.Set(DTOResolver<TDTO>.SetType).Find(id);
        if (entity == null)
            return default(TDTO);
        return DTOResolver<TDTO>.SetMapper.Map(entity);
    }
}

这样做的原因是 DTOResolver&lt;TDTO&gt; 在内存中定义了一个新的静态边界,该边界特定于单个 TDTO 类型,使我们能够为用于该 TDTO 的 Set 注册单个 Type 和单个Mapper 子类实例化一个单例,它被键入到特定的 TSet

【讨论】:

  • 好主意。谢谢你,先生!一个问题:您提到“如果您可以使用静态解析器”。静态解析器有什么问题?
  • 如果它完成了工作,它本身并没有什么问题。如果您使用的是 DI 策略,那么直接访问静态解析器将与该策略相反。然而,添加一个可注入的适配器来解耦这个问题是微不足道的。所以不用担心。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-02-12
  • 2022-11-22
  • 1970-01-01
  • 1970-01-01
  • 2012-04-10
  • 1970-01-01
  • 2021-09-16
相关资源
最近更新 更多