如何创建自定义值注入以将实体映射到视图模型?尝试包括 [英] How do I create a custom value injection to map my entity to my view model? Attempt included

查看:77
本文介绍了如何创建自定义值注入以将实体映射到视图模型?尝试包括的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用ValueInjector(NuGet的最新版本)向我的视图模型注入EntityFramework Code First对象中的数据.我也想做相反的事情,但这是我开始的尝试.

I'm trying to use the ValueInjector (latest version from NuGet) to inject my view model with data from my EntityFramework Code First object. I'll want to do the reverse of this as well, but this is the attempt I'm starting with.

我研究了各种映射,并尝试了许多映射.我还没有找到能满足我需要的东西,我认为我的需求是一个很基本的问题(关于SO的这些问题有好几个,而且每个问题似乎都有不同的答案,这很好.).

I've researched the various mappings and have tried many of them. I haven't found one that does what I need and I think my need is a rather basic one (there are several of these questions on SO and each seems to get a different answer, which is fine.).

我真的已经尽力了.我搜索并拖曳了CodePlex并下载了ProDinner应用程序(启动并运行它,并逐步调试了代​​码).

I've really tried to do my due diligence on this. I've googled and trolled CodePlex and downloaded the ProDinner application (got it up and running and stepped through the code in debug).

我正要拥有自己的ValueInjection类来处理注入器.我将以一种非常友好的方式粘贴我的代码和对象,以便您可以抓取并运行它们.请注意,我有一个使用基本LoopValueInjection的解决方案,但我不喜欢它,因为从实体到映射然后再映射到实体时,需要手动进行注入.我喜欢的ProDinner示例采用了更加模板化的方法,但我无法使其适应我的需求.

I'm at a point where I have my own ValueInjection class to handle the injecton. I'm about to paste my code and objects in a pretty friendly way so you can grab and run them. Mind you I have a solution that uses the base LoopValueInjection, but I don't like it because it'd require manual plumbing for injections going from entity to mapping and then mapping to entity. The ProDinner example had a more templated approach, which I liked, but I couldn't adapt it to my needs.

我认为我的代码在逻辑上搞乱了我,如果源属性类型不是一个简单的对象,我不理解如何强制进行递归注入.在此示例中,Person.Address.*属性将按名称匹配,并在PersonViewModel类上键入这些属性;但是,注入会在Person的属性上循环并尝试匹配Person.Address属性的名称和类型.

I think where my code is messing up logic wise is that I don't understand how to force a recursive injection to occur if the source property type is not a simple object. In this example, the Person.Address.* properties will match by name and type those on the PersonViewModel class; however, the injection loops over the properties on Person and tries to match on the name and type of the Person.Address property.

我以为是线

        Object result = Activator.CreateInstance(c.SourceProp.Type)
            .InjectFrom<CloneInjection>(c.SourceProp.Value);

将执行此递归,但我认为不会.

Would perform this recursion, but I don't think it does.

所以...任何人都可以给我任何有关解决此问题的指导吗?

So...Can anyone give me any direction on how to fix this?

//////  ENTITY MODELS

public class Person
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public virtual Address Address { get; set; }
}

public class Address
{
    public int Id { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Zip { get; set; }
}

//////  VIEW MODEL 

public class PersonViewModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int PersonId { get; set; }
    public int AddressId { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Zip { get; set; } 
}   

////// CUSTOM INJECTOR
public class EntityToViewModel : ConventionInjection
{

    protected override bool Match(ConventionInfo c)
    {
        //ignore int = 0 and DateTime = to 1/01/0001
        if (c.SourceProp.Type == typeof(DateTime) && (DateTime)c.SourceProp.Value == default(DateTime) ||
            (c.SourceProp.Type == typeof(int) && (int)c.SourceProp.Value == default(int)))
            return false;

        if (c.SourceProp.Name == c.TargetProp.Name && c.SourceProp.Value != null)
            return true;

        if (c.SourceProp.Type == typeof(int) &&
            c.TargetProp.Type == typeof(int) )
        {
            if( "id".Equals(c.SourceProp.Name.ToLower()) &&                 
                c.TargetProp.Name.ToLower().EndsWith("id") &&
                c.TargetProp.Name.StartsWith(c.Source.Type.Name))
            return true;
        }

        //Transition logic to SetValue for value types. This should 
        //allow Address values on Person to be set.
        if (!c.SourceProp.Type.IsPrimitive || c.SourceProp.Type.Equals(typeof(string)))
            return true;

        return false;

        //put id logic matching here
        //return c.SourceProp.Name == c.TargetProp.Name && c.SourceProp.Value != null;
    }

    protected override object SetValue(ConventionInfo c)
    {
        //If type is primative or string return the value as is   
        if (c.SourceProp.Type.IsPrimitive || c.SourceProp.Type.Equals(typeof(string)))
            return c.SourceProp.Value;

        Object result = Activator.CreateInstance(c.SourceProp.Type)
            .InjectFrom<CloneInjection>(c.SourceProp.Value);

        //for simple object types create a new instace and apply the clone injection on it
        return result;
    }
}   

////// Program.cs
public class Program
{

    public static void Main(string[] args)
    {
        Person defaultPerson = getDefaultPerson();
        //Throws an error. I'm not sure where in the pipeline this occurs, but 
        //it seems to happen somewhere other than the Match & SetValue method of 
        //my EntityToViewModel injection
        PersonViewModel pvm = CreateFromEntity(defaultPerson);          

        //Works, but want it more generic & without having to 
        //include hardcoded prefix for every non-simple object on my EF Model
        pvm = CreateFromEntityWorking(defaultPerson);
        Console.ReadLine();
    }

    private static PersonViewModel CreateFromEntity(Person person)
    {
        PersonViewModel pvm = new PersonViewModel();
        pvm.InjectFrom<EntityToViewModel>(person);
        return pvm;
    }

    ///WORKING MAPPING BUT SEEMS TOO HARDCODED
    private static PersonViewModel CreateFromEntityWorking(Person person)
    {
        PersonViewModel personvm = new PersonViewModel();

        //Fill out view model properties with the same name as those on Person
        personvm.InjectFrom(new LoopValueInjection().TargetPrefix("Person"), person);

        if (person != null && person.Address != null)
        {
            //Fill out view model properties for the Address
            personvm.InjectFrom(new LoopValueInjection().TargetPrefix("Address"), person.Address);
        }

        return personvm;
    }       

    public static Person getDefaultPerson()
    {
        Person p = new Person();
        Address a = new Address();
        p.Id = 1;
        p.FirstName = "John";
        p.LastName = "McClain";
        a.City = "New York";
        a.State = "New York";
        a.Zip = "55555";
        a.Id = 2;
        p.Address = a;
        return p;
    }   

}

推荐答案

最后找到了我需要的示例.遗憾的是,尽管我进行了所有搜索 我只是现在才登陆这些.我个人没有错.但是,脚踢了多少,我的脚还是酸了.

Finally found the examples I needed. Sadly,despite all my searching I've only just now landed on these. That's no one's fault by my own; however, my foot is sore from how much I've been kicking it.

相关网址:

文档(RTFM) http://valueinjecter.codeplex.com/documentation

整理实例&习俗 http://valueinjecter.codeplex.com/wikipage?title=flattening&referringTitle=Documentation

Flattening Example & Convention http://valueinjecter.codeplex.com/wikipage?title=flattening&referringTitle=Documentation

平整化示例&习俗 http://valueinjecter.codeplex.com/wikipage?title=unflattening&referringTitle=Documentation

Unflattening Example & Convention http://valueinjecter.codeplex.com/wikipage?title=unflattening&referringTitle=Documentation

我的问题的解决方案:

必须在视图模型上使用的约定是顶级属性是 不以其属性名称为前缀,因为该属性名称将存在于实体上.因此,在下面的类中,FirstName,LastName和Id在我的Person实体上都作为顶级属性存在,它们在我的视图模型类中没有前缀. Person.Address属性的City,State,Zip和Id会得到前缀.

The convention that must be used on the view model is that top level properties are not prefixed by their property name as it would exist on the Entity. So, in my class below where FirstName, LastName, and Id all exist as top level properties on my Person entity, they don't get prefixed in my view model class. The City, State, Zip, and Id for the Person.Address property do get prefixed.

奇怪的是,我在尝试实现自己的注入时想到了这个解决方案.我得到了一个从Entity到ViewModel的工作....反之亦然.

Oddly enough, I thought of this solution while I was trying to implement my own injection. I got one working that went from Entity to ViewModel....just not the other way around.

public class PersonViewModelPrefixed
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Id { get; set; }
    public int AddressId { get; set; }
    public string AddressCity { get; set; }
    public string AddressState { get; set; }
    public string AddressZip { get; set; } 
}

public static void Main(string[] args)
{   
        Person defaultPerson = getDefaultPerson();
        PersonViewModelPrefixed defaultPrefixedVm = getDefaultPrefixedViewModel();

        //flatten - Entity to View Model
        PersonViewModelPrefixed pvm = Flatten(defaultPerson);

        //unflatten - View Model to Entity
        Person person2 = Unflatten(defaultPrefixedVm);  
    Console.ReadLine();
}       

//unflatten - View Model to Entity
private static Person Unflatten(PersonViewModelPrefixed personViewModel)
{
    Person p = new Person();
    p.InjectFrom<UnflatLoopValueInjection>(personViewModel);
    return p;
}

//flatten - Entity to View Model
private static PersonViewModelPrefixed Flatten(Person person)
{
    PersonViewModelPrefixed pvm = new PersonViewModelPrefixed();
    pvm.InjectFrom<FlatLoopValueInjection>(person);
    return pvm;
}

因此,鉴于这些细节,是否有人对如何制作Flatten&未展平的方法更通用吗?这就是我接下来要进行的工作.

So, given these details, does any one have some suggestions on how to make the Flatten & Unflatten methods more generic? That's what I'll be working on next.

这篇关于如何创建自定义值注入以将实体映射到视图模型?尝试包括的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆