2010-04-08 39 views
2

我需要编写一个简单的C#.NET应用程序来检索,更新并在Sharepoint列表中插入一些数据。Sharepoint OLE DB - 无法插入记录? “字段不可更新”错误

我不是Sharepoint开发人员,我无法控制我们的Sharepoint服务器。我宁愿不必在proper sharepoint development environment中开发它,只是因为我不想在Sharepoint服务器上部署我的应用程序 - 我宁愿只是在外部访问数据。

无论如何,我发现,你可以使用OLE DB访问SharePoint数据,我试图成功地使用一些ADO.NET:

var db = DatabaseFactory.CreateDatabase(); 
DataSet ds = new DataSet(); 
using (var command = db.GetSqlStringCommand("SELECT * FROM List")) 
{ 
    db.LoadDataSet(command, ds, "List"); 
} 

上述作品。

然而,当我尝试插入:

using (var command = db.GetSqlStringCommand("INSERT INTO List ([HeaderName], 
    [Description], [Number]) VALUES ('Blah', 'Blah', 100)")) 
{ 
    db.ExecuteNonQuery(command); 
} 

我得到这个错误:

Cannot update 'HeaderName'; field not updateable. 

我做了一些谷歌搜索,显然you cannot insert data through OLE DB

有谁知道是否有一些可能的解决方法?

我可以尝试使用Sharepoint Web服务,但我最初尝试过,并且正在进行身份验证。这是我唯一的选择吗?

+1

大家好,只是为了让你知道,我得到更好的结果IMEX = 0在ConnectionString(不知道为什么,因为我没有发现任何有关此参数的文档)。我希望这有帮助。问候 – 2011-05-09 16:27:39

回答

2

由于许可的SharePoint,我不会直接插入记录到后端数据库!,在任何情况下,使用本地的SharePoint Web服务,即http://server/site/_vti_bin/Lists.asmx

的SharePoint有许多Web服务,你可以打电话几乎可以做任何SharePoint本身的工作。

每个网站集都可以使用他们自己的Web服务,不需要在服务器上进行代码编译,不需要组件,不需要直接更改数据库......它们非常易于使用,并且Microsoft和其他。

您需要附加一个具有正确用户详细信息的普通NetworkCredentials类,并将其绑定到实例化的Web Service类。

如果您的SharePoint使用的是SQL Server,您可以尝试使用SqlClient命名空间而不是OLEDB,Web服务的优点在于您不必过多担心网站集的哪些内容数据库,尤其是如果SharePoint在实时创建它们而不是实际指定它的管理员。

希望这有助于。

干杯。如果需要的话

+0

@Ivan Dormain,是的,我可能会使用Web服务。当我之前尝试使用它们时,我正在使用正确的用户详细信息附加NetworkCredentials类,但它仍然给我一个NTLM身份验证错误。我想我会发布这个作为一个单独的StackOverflow问题,如果我无法弄清楚。 谢谢! – Pandincus 2010-04-09 12:35:48

+0

嘿Pandincus你的代码是这样的: //实例化Web服务 SPListService.Lists lists = new SPListLoaderService.SPListService.Lists(); //将适当的证书绑定到Web服务 lists.Credentials = new NetworkCredential(data.UserName,data.Password,data.Domain); //设置列表对象URI lists.Url = data.URI.TrimEnd('/')+“/_vti_bin/lists.asmx”; – 2010-04-09 14:04:19

2

OLEDB的支持对我来说是非常新闻,我猜是因为它不是常用的,因为它是只读的本质。我倾向于在服务器本身上使用对象模型。这不是太麻烦 - 你只需要包含一个引用,并且使用Web服务要容易得多。如果你想外部运行,但Web服务是你的唯一选择。要么或者将这两种方法结合起来,开发自己的Web服务,该服务在IIS下的服务器上运行并包含对象模型代码。

+0

@丹,感谢您的意见。问题是,我不知道部署到Sharepoint服务器的具体情况,我无法控制公司的服务器,所以我必须通过适当的渠道来部署软件。不是不可能的,但是如果我完全可以避免这种情况就容易多了 我会再看看Web服务 - 我在通过NTLM进行身份验证时,OLE DB似乎是一条更简单的道路:-P – Pandincus 2010-04-08 22:27:08

0

我还使用假冒:

using System.Security.Principal; 

使用System.Runtime.InteropServices;

#region Constants 
    public const int LOGON32_LOGON_INTERACTIVE = 2; 
    public const int LOGON32_PROVIDER_DEFAULT = 0; 
#endregion 

public WindowsImpersonationContext impersonationContext; 

#region Win32 API 
    [DllImport("advapi32.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] 
    public static extern int LogonUserA(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken); 
    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)] 
    public static extern int DuplicateToken(IntPtr ExistingTokenHandle, int ImpersonationLevel, ref IntPtr DuplicateTokenHandle); 
    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)] 
    public static extern bool RevertToSelf(); 
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)] 
    public static extern long CloseHandle(IntPtr handle); 
    #endregion 

public bool Impersonate(string userName, string domain, string password) 
    { 
     try 
     { 
      bool functionReturnValue = false; 
      WindowsIdentity tempWindowsIdentity = default(WindowsIdentity); 
      IntPtr token = IntPtr.Zero; 
      IntPtr tokenDuplicate = IntPtr.Zero; 
      functionReturnValue = false; 
      if (RevertToSelf()) 
      { 
       if (LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token) != 0) 
       { 
        if (DuplicateToken(token, 2, ref tokenDuplicate) != 0) 
        { 
         tempWindowsIdentity = new WindowsIdentity(tokenDuplicate); 
         impersonationContext = tempWindowsIdentity.Impersonate(); 
         if ((impersonationContext != null)) 
         { 
          functionReturnValue = true; 
         } 
        } 
       } 
      } 
      if (!tokenDuplicate.Equals(IntPtr.Zero)) 
      { 
       CloseHandle(tokenDuplicate); 
      } 
      if (!token.Equals(IntPtr.Zero)) 
      { 
       CloseHandle(token); 
      } 

      return functionReturnValue; 
     } 
     catch (Exception ex) 
     { 
      SQMSLog.WriteLogEntry(ex.Message, "SYSTEM"); 
      return false; 
     } 
    } 

public void UndoImpersonate() 
    { 
     impersonationContext.Undo(); 
    } 

调用模拟功能第一则:

//Add Miscellaneous Data Details 
      data.ListNameEx = Settings.Default.SPListLoader_List_Name; 
      //Instantiate the Web Service 
      SPListService.Lists lists = new SPListLoaderService.SPListService.Lists(); 
      //Bind Appropriate Credentials to the Web Service 
      lists.Credentials = new NetworkCredential(data.UserName, data.Password, data.Domain); 
      //Set the List Object URI 
      lists.Url = data.URI.TrimEnd('/') + "/_vti_bin/lists.asmx"; 

一旦完成,你需要释放内容:

UndoImpersonate(); 

以上是非常重要的,一旦你有你执行什么都称为Impersonate();将在该用户凭据下运行。

希望这有助于。

干杯。

+0

@伊曼多曼,嘿,谢谢你的信息。我没有使用Impersonator来尝试它,但我只是实现了它(我在一个不同的项目中使用了类似的Impersonator类),但它仍然不起作用。 这属于另一个问题,但 - 我会张贴它,并在这里包括一个链接,如果你想帮助:-D – Pandincus 2010-04-09 15:28:59

+0

@Ivan Dormain,如果你有兴趣,http://stackoverflow.com/questions/2608887/sharepoint-web-services-the-http-request-is-unauthorized-with-client-authentic 谢谢! – Pandincus 2010-04-09 16:05:41

1

同样的事情用ADOINSERT INTO声明

如果您在访问链接到列表中,你可以使用它作为一个本地访问表是真的。

Dim db as Database 
Set db = CurrentDb 
db.Execute "INSERT INTO [List Name]..." 
0

确实没有数据可以通过OLE DB更新吗?我认为您链接的文章特指multi-valued ("complex") data types,这是Access2007以上版本(即SharePoint使用Access数据库)中Access数据引擎的一项功能。看看this article,它使用DAO(ACEDAO库)来处理多值数据。