【问题标题】:Sharepoint OLE DB - cannot insert records? "Field not updateable" errorSharepoint OLE DB - 无法插入记录? “字段不可更新”错误
【发布时间】:2010-04-08 19:08:16
【问题描述】:

我需要编写一个简单的 C# .NET 应用程序来在 Sharepoint 列表中检索、更新和插入一些数据。

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

无论如何,我发现你可以使用 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 服务,但我最初尝试过,并且在进行身份验证时遇到了麻烦。这是我唯一的选择吗?

【问题讨论】:

  • 大家好,只是为了让你们知道我在 ConnectionString 中使用 IMEX=0 得到了更好的结果(不知道为什么,因为我没有找到有关此参数的文档)。我希望这有帮助。问候

标签: c# sql sharepoint ado.net oledb


【解决方案1】:

由于 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动态创建它们,而不是由管理员实际指定它。

希望这会有所帮助。

干杯。

【讨论】:

  • @Ivan Dormain,是的,我可能会使用 Web 服务。当我之前尝试使用它们时,我在 NetworkCredentials 类中附加了正确的用户详细信息,但它仍然给我一个 NTLM 身份验证错误。如果我无法弄清楚,我想我会将其作为一个单独的 StackOverflow 问题发布。谢谢!
  • Hey Pandincus,您的代码看起来像吗: //实例化 Web 服务 SPListService.Lists lists = new SPListLoaderService.SPListService.Lists(); //将适当的凭据绑定到Web服务列表.Credentials = new NetworkCredential(data.UserName, data.Password, data.Domain); //设置List Object URI lists.Url = data.URI.TrimEnd('/') + "/_vti_bin/lists.asmx";
【解决方案2】:

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

【讨论】:

  • @Dan,感谢您的意见。问题是,我不知道部署到 Sharepoint 服务器的细节,而且我无法控制我公司的服务器,所以我必须通过适当的渠道来部署软件。并非不可能,但如果我能完全避免这种情况会容易得多。我再看看网络服务——我在通过 NTLM 进行身份验证时遇到问题,而 OLE DB 似乎是一条更容易的道路:-P
【解决方案3】:

使用ADOINSERT INTO 语句也是如此

如果您链接到 Access 中的列表,则可以将其用作本机访问表。

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

【讨论】:

    【解决方案4】:

    使用 OLEDB写入到 SharePoint 列表的解决方案是在连接字符串中指定 IMEX=0。

    http://www.connectionstrings.com/sharepoint

    【讨论】:

      【解决方案5】:

      如果需要,我也会使用模拟:

          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();将在该用户凭据下运行。

      希望对您有所帮助。

      干杯。

      【讨论】:

      • @Ivan Dormain,嘿,谢谢你的信息。我没有尝试使用 Impersonator,但我只是实现了它(我在另一个项目中使用了类似的 Impersonator 类),但它仍然无法正常工作。不过,这属于另一个问题-如果您愿意提供帮助,我将在此处发布并包含一个链接:-D
      • @Ivan Dormain,如果你有兴趣,stackoverflow.com/questions/2608887/… 谢谢!
      【解决方案6】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-11
        • 1970-01-01
        • 1970-01-01
        • 2013-12-27
        • 2016-11-16
        • 1970-01-01
        相关资源
        最近更新 更多