2017-09-20 47 views
1

我有很多接口,每个都有它2个实现:铸造从一个2种泛型类型的其他

public interface Foo{/**/} 

public class ModelFoo : Foo {/**/} 

public class ViewModelFoo : Foo {/**/} 

现在我有一个泛型函数中有一个repositoryInterface和2个实现:

public interface Repository 
    { 
     ICollection<TModel> GetAll<TModel>(); 
    } 

    public class ModelRepository : Repository 
    { 
     private IDictionary<Type, Type> typeMapping = new Dictionary<Type, Type>(); 
     private DbContext context; 
     public ICollection<TModel> GetAll<TModel>() 
     { 
      var implType = typeMapping[typeof(TModel)]; 
      var ctxSet = context.Set(implType); 

      return new EFWrapCollection<TModel>(Enumerable.Cast<object>(ctxSet).ToList()); 
     } 

    } 

接口的第一个实现将加载数据库中的所有模型。字典typemapping需要在接口类型和具体类型之间进行类型映射。 EFWrapCollection将参数包装为TModel类型。

typemapping有对如下:

(typeof(Foo), typeof(ModelFoo)), 
(typeof(Bar), typeof(ModelBar)), 
... 

的使用情况如下:

 var rep = new ModelRepository(context); 
     rep.GetAll<Foo>(); 

这将返回所有ModelFoo的从数据库中与typeparameter 。现在,我要做到以下几点:

public class ViewModelRepository : Repository 
    { 
     private IDictionary<Type, Type> typeMapping = new Dictionary<Type, Type>(); 
     private Repository repository; 
     public ICollection<TModel> GetAll<TModel>() 
     { 
      var result = repository.getAll<TModel>(); 
      //now i have the problem that i need a cast 
      //but I dont know hot to achieve it 
     } 
    } 

在这个仓库类也有一个typemapping。此属性包含接口类型和视图模型类型之间的所有映射:

(typeof(Foo), typeof(ViewModelFoo)), 
(typeof(Bar), typeof(ViewModelBar)), 
..... 

演员应该是投给Viewmodeltype。我知道如何投2个具体类,但在这里我有问题,这个存储库是通用的,我不知道类型。

编辑

为什么我需要投(或映射):

在数据库中,只有类型模式的模式,我想投(或地图)类型型号纳入型号ViewModel

+1

看起来你应该做映射,而不是铸造。 – juharr

+0

@juharr是的,映射也许是更好的术语。但我不知道如何实现这里的映射 –

+1

我目前不确定你到底想要做什么。你的方法'GetAll ()'返回'ICollection '。也许你可以在'repository.getAll ()'返回的值上调用'.ToList()'。但我相信这不是你所期望的。目前还不清楚如何决定返回'ModelFoo'还是'ViewModelFoo'。我的猜测是调用'repository.getAll ()'是错误的,令我困惑。也许你试着调用'repository.getAll ()'(不编译:-),但是你不知道该怎么做。我对吗?是的,也许我可以帮助你。否:请澄清。 –

回答

0

你在混合苹果和橘子。您不应该在存储库内跟踪类型。存储库应该特定于它的工作类型。

您可以改为创建一个通用存储库并将其传递给它应该使用的类型。上下文有一个通用的Set<T>方法,你可以充分利用:

public class Repository<T> 
{ 
    private DbContext context; 
    public ICollection<T> GetAll() 
    {    
     var items = context.Set<T>(); 
     return new EFWrapCollection<T>(items); 
    } 
} 

我不完全知道为什么你正在使用EFWrapCollection但我猜你有你的理由。

我猜你现在已经意识到,除非你适当地管理上下文的生命周期,否则传递EF对象并不是一个好主意。类型映射可以用许多不同的方式处理。我建议你看看AutoMapper。您可以创建对象映射为你的类,让AutoMapper做的大部分工作,那么对于那些不那么直接的属性提供自定义映射:

https://cpratt.co/using-automapper-getting-started/

这是从一个快速的摘录链接,给你一个想法:

public static class AutoMapperConfig 
{ 
    public static void RegisterMappings() 
    { 
     AutoMapper.Mapper.CreateMap<ModelFoo, ViewModelFoo>() 
      .ForMember(dest => dest.Author, 
         opts => opts.MapFrom(src => src.Author.Name)); 
    } 
} 

顺便说一句,如果你按照惯例,世界将欣赏它,并用字母前缀的接口I(例如IRepository)。它确实使阅读代码变得更容易。祝你好运!