RIA 服务:插入多个表示模型对象 [英] RIA Services: Inserting multiple presentation-model objects

查看:22
本文介绍了RIA 服务:插入多个表示模型对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用基于 LINQ to SQL 类的演示模型通过 RIA 服务共享数据.在 Silverlight 客户端上,我创建了几个新实体(专辑和艺术家),将它们相互关联(通过将专辑添加到艺术家的专辑收藏,或在专辑上设置 Artist 属性 - 任一作品),添加将它们添加到上下文中,并提交更改.

在服务器上,我收到两个单独的 Insert 调用 - 一个用于专辑,另一个用于艺术家.这些实体是新的,因此它们的 ID 值都设置为默认的 int 值(0 - 请记住,这取决于我的数据库,这可能是数据库中的有效 ID),因为据我所知,您没有设置 ID对于客户端上的新实体.如果我通过我的 RIA 服务将 LINQ 转移到 SQL 类,这一切都会正常工作,因为即使专辑插入包含艺术家,艺术家插入包含专辑,两者都是实体并且 L2S 上下文识别它们.但是,对于我的自定义表示模型对象,我需要将它们转换回 LINQ to SQL 类维护流程中的关联,以便将它们添加到 L2S 上下文中.

简而言之,据我所知,这是不可能的.每个实体都有自己的 Insert 调用,但您无法只插入一个实体,因为没有 ID,关联就会丢失.如果数据库使用 GUID 标识符,那就是另一回事了,因为我可以在客户端设置这些标识符.

这是可能的,还是我应该追求另一种设计?

解决方案

如果您创建了正确的父子关联,您只需要跟踪插入的表示模型(PM)-实体关系:

下午:

公共类父级{[钥匙]公众号?父 ID { 获取;放;}[包括][作品][关联(Parent_1-*_Child",ParentID",ParentID",IsForeignKey = false)]公共 IEnumerable儿童{得到;放;}}公开课儿童{[钥匙]公众号?ChildID { 得到;放;}[包括][关联(Parent_1-*_Child",ParentID",ParentID",IsForeignKey = true)]公共父父{获取;放;}}

务必使用 [Composition] 强制 WCF RIA 调用 DomainService 上的 InsertChild 方法.

银光:

<代码>...public Child NewChild(Parent parent){返回新的孩子{ParentID = parent.ParentID,父母 = 父母,};}...public void SubmitChanges(){DomainContext.SubmitChanges(SaveComplete, null);}...

如果 Parent 不是新的,它将有一个 ParentID.如果是新的,则父 ID 将为空.通过将 Child.Parent 设置为新父级的引用,RIA 了解您正在尝试执行的操作,并在将引用发送到服务器后保留该引用.

服务器上的域服务:

[EnableClientAccess]公共类 FamilyDomainService : DomainService{私有只读 IDictionary_insertedObjectMap;公共无效插入父(父父){ParentEntity parentEntity = new ParentEntity();ObjectContext.AddToParents(parentEntity);_insertedObjectMap[parent] = parentEntity;ChangeSet.Associate(parent, parentEntity, (p, e) => p.ParentID = e.ParentID;}public void InsertChild(Child child){var childEntity = new ChildEntity();if (child.ParentID.HasValue)//当 Parent 已经存在但 Child 是新的时使用{childEntity.ParentID = child.ParentID.GetValueOrDefault();ObjectContext.AddToChildren(childEntity);}else//在同一个请求中插入父级和子级时使用{ParentEntity parentEntity;if (child.Parent != null && _insertedObjectMap.TryGetValue(child.Parent, out parentEntity)){parentEntity.Children.Add(childEntity);ChangeSet.Associate(child, childEntity, (c, e) => c.ParentID = e.Parent.ParentID);}别的{throw new Exception("无法插入子级:ParentID 为空且无法找到父级父级");}}_insertedObjectMap[child] = childEntity;ChangeSet.Associate(child, childEntity, (c, e) => c.ChildID = e.ChildID );}protected override bool PersistChangeSet(){ObjectContext.SaveChanges();_insertedObjectMap.Clear();返回真;}}

这里有两个重要的部分.首先,'_insertedObjectMap' 存储没有设置 ID 的新插入实体之间的关系.由于您是在事务中执行此操作并且对数据库进行单次调用,因此只有在插入所有实体后才会设置 ID.通过存储关系,子 PM 可以使用数据库找到父 PM 的实体版本.Child 实体被添加到 Parent 实体的 Children 集合中,LINQToSQL 或 LINQToEnityFramework 应该为您处理外键.

第二部分是在事务提交后关联更改.在Parent和Child都提交的场景下,一定要记得在Child上设置ParentID外键.

我的 ChangeSet.Associate() 信息来自:http://blogs.msdn.com/deepm/archive/2009/11/20/wcf-ria-services-presentation-model-explained.aspx>

I'm sharing data via RIA services using a presentation model on top of LINQ to SQL classes. On the Silverlight client, I created a couple of new entities (album and artist), associated them with each other (by either adding the album to the artist's album collection, or setting the Artist property on the album - either one works), added them to the context, and submitted changes.

On the server, I get two separate Insert calls - one for the album and one for the artist. These entitites are new so their ID values are both set to the default int value (0 - keep in mind that depending on my DB, this could be a valid ID in the DB) because as far as I know you don't set IDs for new entities on the client. This all would work fine if I was transferring the LINQ to SQL classes via my RIA services, because even though the Album insert includes the Artist and the Artist insert includes the Album, both are Entities and the L2S context recognizes them. However, with my custom presentation model objects, I need to convert them back to the LINQ to SQL classes maintaining the associations in the process so they can be added to the L2S context.

Put simply, as far as I can tell, this is impossible. Each entity gets its own Insert call, but there's no way you can just insert the one entity because without IDs the associations are lost. If the database used GUID identifiers it would be a different story because I could set those on the client.

Is this possible, or should I be pursuing another design?

解决方案

If you create the correct parent-child associations, you'll just need to track the inserted presentation model(PM)-entity relationships:

PM's:

public class Parent
{
    [Key]
    public int? ParentID { get; set; }

    [Include]
    [Composition]
    [Association("Parent_1-*_Child", "ParentID", "ParentID", IsForeignKey = false)]
    public IEnumerable<Child> Children { get; set; }
}

public class Child
{
    [Key]
    public int? ChildID { get; set; }

    [Include]
    [Association("Parent_1-*_Child", "ParentID", "ParentID", IsForeignKey = true)]
    public Parent Parent { get; set; }
}

Be sure to use [Composition] to force WCF RIA to call the InsertChild method on the DomainService.

Silverlight:

...
public Child NewChild(Parent parent)
{
    return new Child
                {
                    ParentID = parent.ParentID,
                    Parent = parent,
                };
}
...
public void SubmitChanges()
{
    DomainContext.SubmitChanges(SaveComplete, null);
}
...

If the Parent is not new, it will have a ParentID. If it is new, the Parent ID will be null. By setting the Child.Parent to the reference of the new Parent, RIA understands what you are trying to do preserves the reference after it has been sent to the server.

DomainService on the server:

[EnableClientAccess]
public class FamilyDomainService : DomainService
{
    private readonly IDictionary<object, EntityObject> _insertedObjectMap;

    public void InsertParent(Parent parent)
    {
        ParentEntity parentEntity = new ParentEntity();

        ObjectContext.AddToParents(parentEntity);
        _insertedObjectMap[parent] = parentEntity;

        ChangeSet.Associate(parent, parentEntity, (p, e) => p.ParentID = e.ParentID;
    }

    public void InsertChild(Child child)
    {
        var childEntity = new ChildEntity();

        if (child.ParentID.HasValue) // Used when the Parent already exists, but the Child is new
        {
            childEntity.ParentID = child.ParentID.GetValueOrDefault();
            ObjectContext.AddToChildren(childEntity);
        }
        else // Used when the Parent and Child are inserted on the same request
        {
            ParentEntity parentEntity;
            if (child.Parent != null && _insertedObjectMap.TryGetValue(child.Parent, out parentEntity))
            {
                parentEntity.Children.Add(childEntity);
                ChangeSet.Associate(child, childEntity, (c, e) => c.ParentID = e.Parent.ParentID);
            }
            else
            {
                throw new Exception("Unable to insert Child: ParentID is null and the parent Parent cannot be found");
            }
        }

        _insertedObjectMap[child] = childEntity;

        ChangeSet.Associate(child, childEntity, (c, e) => c.ChildID = e.ChildID );
    }

    protected override bool PersistChangeSet()
    {
        ObjectContext.SaveChanges();
        _insertedObjectMap.Clear();
        return true;
    }
}

The two important pieces here. First, the '_insertedObjectMap' stores the relationship between newly inserted entities that do not have the ID set. Since you are doing this in a transaction and single call to the DB, the ID will only be set after all entities have been inserted. By storing the relationship, the Child PM can find the entity version of the Parent PM using the database. The Child entity is added to the Children collection on the Parent entity and LINQToSQL or LINQToEnityFramework should handle the foreign key for you.

The second piece is associating the changes after the transaction is committed. In the scenario where the Parent and Child are both submitted, you must remember to set the ParentID foreign key on the Child.

My info from the ChangeSet.Associate() came from: http://blogs.msdn.com/deepm/archive/2009/11/20/wcf-ria-services-presentation-model-explained.aspx

这篇关于RIA 服务:插入多个表示模型对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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