2

我遇到问题已经有一段时间了,我已经用尽了所有方法来为自己解决这个问题。

我在 MS Sharepoint 2010 环境中有 2 个列表,其中包含医疗组的个人医生数据……没什么特别的,主要是文本字段和一些查找选择字段。

我正在尝试编写一个程序,将数据从列表 A 迁移到列表 B。我正在使用 LINQ to Sharepoint 来完成此操作。一切都编译得很好,但是当它运行并点击 SubmitChanges() 方法时,我收到一个运行时错误,指出:

“必须在提交更改之前添加/附加对象图中的所有新实体。”

这个问题一定超出了我的 C# 知识范围,因为我根本找不到解决方案。问题肯定源于某些列属于“查找”类型的事实,因为当我在 LINQ 查询中创建新的“医师”实体时,如果我注释掉处理查找列的字段,一切都会运行完美。

在包含查找列的情况下,如果我在 SubmitChanges() 方法之前调试并点击断点,我可以查看从旧列表创建的新“医师”实体和字段,包括查找列中的数据,看起来不错,数据以我想要的方式在那里,每当它尝试用新实体实际更新新列表时,它就会消失。

我尝试了几种解决此错误的方法,但均无济于事。特别是,我尝试创建一个全新的 EntityList 列表并在创建每个新的“医师”实体后调用 Attach() 方法,但无济于事,它只是让我绕着一堆圈子,追逐其他错误,例如“ID 不能为空”、“不能插入已删除的实体”等,

我现在不比我第一次遇到此错误时更进一步,任何人都可以提供的任何帮助肯定会受到赞赏。

这是我的代码:

using (ProviderDataContext ctx = new ProviderDataContext("http://dev"))
        {

            SPSite sitecollection = new SPSite("http://dev");
            SPWeb web = sitecollection.OpenWeb();
            SPList theOldList = web.Lists.TryGetList("OldList_Physicians");

             //Create new Physician entities.
                    foreach(SPListItem l in theOldList.Items)
                    {
                        PhysiciansItem p = new PhysiciansItem()
                        {
                            FirstName = (String)l["First Name"],
                            Title = (String)l["Last Name"],  
                            MiddleInitial = (String)l["Middle Init"],
                            ProviderNumber = Convert.ToInt32(l["Provider No"]),
                            Gender = ConvertGender(l),
                            UndergraduateSchool =(String)l["UG_School"],
                            MedicalSchool = (String)l["Med_School"], 
                            Residency = (String)l["Residency"],
                            Fellowship = (String)l["Fellowship"], 
                            Internship = (String)l["Internship"],    
                            PhysicianType = ConvertToPhysiciantype(l),
                            Specialty = ConvertSpecialties(l),
                            InsurancesAccepted = ConvertInsurance(l),
                        };
                   ctx.Physicians.InsertOnSubmit(p);
                    }

                    ctx.SubmitChanges(); //this is where it flakes out
        }
    }


     //Theses are conversion functions that I wrote to convert the data from the old list to the new lookup columns.

    private Gender ConvertGender(SPListItem l)
    {
        Gender g = new Gender();
        if ((String)l["Sex"] == "M")
        {
            g = Gender.M;
        }
        else g = Gender.F;
        return g;

    }

    //Process and convert the 'Physician Type', namely the distinction between MD (Medical Doctor) and 
    //DO (Doctor of Osteopathic Medicine).  State Regualtions require this information to be attached 
    //to a physician's profile.
    private ProviderTypesItem ConvertToPhysiciantype(SPListItem l)
    {
        ProviderTypesItem p = new ProviderTypesItem();
        p.Title = (String)l["Provider_Title:Title"];
        p.Intials = (String)l["Provider_Title"];

        return p;
    }

    //Process and convert current Specialty and SubSpecialty data into the single multi-choice lookup column
    private EntitySet<Item> ConvertSpecialties(SPListItem l)
    {
        EntitySet<Item> theEntityList = new EntitySet<Item>();
        Item i = new Item();
        i.Title = (String)l["Provider Specialty"];
        theEntityList.Add(i);            

        if ((String)l["Provider SubSpecialty"] != null)
        {
            Item theSubSpecialty = new Item();
            theSubSpecialty.Title = (String)l["Provider SubSpecialty"];
            theEntityList.Add(theSubSpecialty);
        }

        return theEntityList;
    }


    //Process and add insurance accepted.
    //Note this is a conversion from 3 boolean columns in the SP Environment to a multi-select enabled checkbox
    //list.
    private EntitySet<Item> ConvertInsurance(SPListItem l)
    {
        EntitySet<Item> theEntityList = new EntitySet<Item>();
           if ((bool)l["TennCare"] == true)
                {
                    Item TenncareItem = new Item();
                    TenncareItem.Title = "TennCare";
                    theEntityList.Add(TenncareItem);

                }
         if ((bool)l["Medicare"] == true)
                {
                    Item MedicareItem = new Item();
                    MedicareItem.Title = "Medicare";
                    theEntityList.Add(MedicareItem);
                }
         if ((bool)l["Commercial"] == true)
                {
                    Item CommercialItem = new Item();
                    CommercialItem.Title = "Commercial";
                    theEntityList.Add(CommercialItem);
                }
         return theEntityList;

   }
}
4

1 回答 1

2

所以这可能不是您正在寻找的答案,但它是过去对我有用的。我发现使用 Linq to Sharepoint 更新查找字段非常令人沮丧。它经常不起作用,或者不能有效地工作(迫使我通过 ID 查询项目只是为了设置查找值)。

您可以设置实体,使其具有用于查找 id 的 int 属性(对于每个查找字段)和用于查找值的字符串属性。如果,当您使用 SPMetal 生成实体时,您没有生成正在查找的列表,那么它将自行执行此操作。我喜欢做的是(以你的实体为例)

  1. Physicians为某个临时文件夹中的一个列表 ( ) 生成实体
  2. 为每个查找(或我感兴趣的查找)提取查找 id 和值的属性(也将有私有的支持字段,也需要随之而来)
  3. 在我的实际项目文件中创建一个部分类文件Physicians,以便正常重新生成整个 SPMetal 文件(不限于该列表)不会覆盖更改
  4. 将查找 id 和值属性粘贴到此部分Physicians类中。

现在,每个查找字段都有 3 个属性。例如,因为PhysicianType会有:

  • PhysicianType,这是当前存在的那个。这在查询数据时非常有用,因为您可以非常轻松地执行连接等。
  • PhysicianTypeId如果您只需要 ID,这有时对查询很有用,因为它使它更简单一些,但大多数情况下,我在设置值时都会使用它。要设置查找字段,您只需设置 ID。这很容易,并且根据我的经验,在实际工作(正确)方面有着良好的记录。
  • PhysicianTypeValue如果您只需要查找值作为字符串,这在执行查询时可能很有用(这意味着它将是原始值,而不是如果它是多值字段或用户字段等已经解析的东西。有时我'我宁愿自己解析它,或者只是在开发时看看底层价值是什么。即使你不使用它并使用第一个属性,我也经常随身携带它,因为我已经做了大部分努力把这个PhysicianTypeId领域带过来。

这似乎有点 hacky,并且与 linq-to-SharePoint 的一般设计相反。我同意,但它也具有实际工作的优点,并且实际上并不那么难(一旦你掌握了它的节奏并了解了究竟需要复制什么以将属性从一个文件移动到另一个文件)。

于 2012-08-29T16:33:51.173 回答