繁体   English   中英

如果在数据库中插入了新记录,如何更新SharePoint Online列表?

[英]How to update a SharePoint Online list if a new record is inserted in the database?

我有一个保存个人信息的MySQL数据库。 每当雇用新员工时,他/她都会填写一些个人信息,并将这些数据存储在表中。

经过一番研究(并且由于我无权访问其他系统-只有数据库),计划是构建一个C#控制台应用程序,该应用程序检索数据并针对SharePoint列表进行检查。 如果以前数据库中不存在新记录,那么我想更新列表(创建新项)。

请注意,如果SharePoint列表包含更多列,则该表包含其他手册信息。

我已经针对数据库发布了连接代码,以及如何检索数据。

如何检查SharePoint列表中是否存在该项目? 有人能够提供包含用于创建和插入新项目的代码的答案吗? 我有两列(在数据库和SP列表中)可以用作主键。

有一个支持CRUD的REST API,所以我想这应该很容易。

SharePoint列表:
SharePoint列表

using System;
using System.Windows;

public class DbConnection
{
    private String databaseName;
    private String serverAddress;
    private String pwd;
    private String userName;
    private Boolean connected;
    private MySql.Data.MySqlClient.MySqlConnection conn;

    public DbConnection(String databaseName, String serverAddress, String pwd, String userName)
    {
        this.databaseName = databaseName;
        this.serverAddress = serverAddress;
        this.pwd = pwd;
        this.userName = userName;
        connected = false;
    }

    public void Connect()
    {
        if (connected == true)
        {
            Console.Write("There is already a connection");
        }
        else
        {
            connected = false;
            String connectionString = "server=" + serverAddress + ";" + "database=" + databaseName + ";" + "uid=" + userName + ";" + "pwd=" + pwd + ";";
            Console.WriteLine(connectionString);

            try
            {
                conn = new MySql.Data.MySqlClient.MySqlConnection(connectionString);
                conn.Open();
                Console.Write("Connection was succesfull");
            }
            catch (MySql.Data.MySqlClient.MySqlException ex)
            {
                 MessageBox.Show(ex.Message);
            }
        }
    }

    public Boolean IsConnected()
    {
        return connected;
    }

    public MySql.Data.MySqlClient.MySqlConnection getConnection()
    {
        return conn;
    }

    public void Close()
    {
        conn.Close();
        connected = false;
    }
}

然后我像这样检索数据:

using MySql.Data.MySqlClient;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace daily_CC_SP_update
{
    class Program
    {
        static void Main()
        {
            DbConnection mySQLConn = new DbConnection(dbName, serverAddress, pwd, userName);
            mySQLConn.Connect();

            string sqlQuery = "SELECT * FROM tbl_CC_SP";
            MySqlCommand sqlCom = new MySqlCommand(sqlQuery, mySQLConn.getConnection());
            MySqlDataReader reader = sqlCom.ExecuteReader();

            Console.WriteLine("Following output from DB");
            if(reader.Read())
            {
                Console.WriteLine(reader.GetString(0));
            }

            //Keep the console alive until enter is pressed, for debugging
            Console.Read();
            mySQLConn.Close();

        }
    }
}

我将在数据库中创建一个视图以检索正确的数据。

首先只是要澄清一下:) ..您正在使用SharePoint内部部署吗? 因此,我们可以使用农场解决方案。 如果是,那么我将通过休闲解决方案解决此问题。 我将开发一个SPJob(SharePoint Timer作业)。 它可能仅包含在“农场”解决方案中。 基本上看起来像这样:

  1. 在解决方案中创建Farm项目
  2. 添加从SPJobDefinition继承的类,并将您的逻辑放入您需要重写的Execute方法中(在此方法中,创建一个标准的SQL连接并从mySQL db查询此表,然后与您的SPList进行比较:))(也可以在这里一个好的方法是将该连接字符串的某些凭据存储在某个配置站点上或某个位置的某些SPList中...不对其进行硬编码;))例如

public class CustomJob : SPJobDefinition
{
    public CustomJob() : base() { }
    public CustomJob(string jobName, SPService service) : base(jobName, service, null, SPJobLockType.None)
    {
        this.Title = jobName;
    }
    public CustomJob(string jobName, SPWebApplication webapp) : base(jobName, webapp, null, SPJobLockType.ContentDatabase)
    {
        this.Title = jobName;
    }
    public override void Execute(Guid targetInstanceId)
    {
        SPWebApplication webApp = this.Parent as SPWebApplication;
        try
        {
            // Your logic here
        }
        catch (Exception ex)
        {
            SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("CustomJob - Execute", TraceSeverity.Unexpected, EventSeverity.Error), TraceSeverity.Unexpected, ex.Message, ex.StackTrace);
        }
    }
}
  1. 向范围为webApplication的解决方案中添加新功能,并向该功能添加事件接收器
  2. 在功能处于活动状态时注册您的Timer作业(记住在处于非活动状态时将其删除:)

public class Feature2EventReceiver : SPFeatureReceiver
{
    const string JobName = "CustomJob";
    public override void FeatureActivated(SPFeatureReceiverProperties properties)
    {
        try
        {
            SPSecurity.RunWithElevatedPrivileges(delegate ()
            {
                // add job
                SPWebApplication parentWebApp = (SPWebApplication)properties.Feature.Parent;
                DeleteExistingJob(JobName, parentWebApp);
                CreateJob(parentWebApp);
            });
        }
        catch (Exception ex)
        {
            SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("CustomJob-FeatureActivated", TraceSeverity.Unexpected, EventSeverity.Error), TraceSeverity.Unexpected, ex.Message, ex.StackTrace);
        }
    }
    public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
    {
        lock (this)
        {
            try
            {
                SPSecurity.RunWithElevatedPrivileges(delegate ()
                {
                    // delete job
                    SPWebApplication parentWebApp = (SPWebApplication)properties.Feature.Parent;
                    DeleteExistingJob(JobName, parentWebApp);
                });
            }
            catch (Exception ex)
            {
                SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("CustomJob-FeatureDeactivating", TraceSeverity.Unexpected, EventSeverity.Error), TraceSeverity.Unexpected, ex.Message, ex.StackTrace);
            }
        }
    }
    private bool CreateJob(SPWebApplication site)
    {
        bool jobCreated = false;
        try
        {
            // schedule job for once a day
            CustomJob job = new CustomJob(JobName, site);
            SPDailySchedule schedule = new SPDailySchedule();
            schedule.BeginHour = 0;
            schedule.EndHour = 1;
            job.Schedule = schedule;

            job.Update();
        }
        catch (Exception)
        {
            return jobCreated;
        }
        return jobCreated;
    }
    public bool DeleteExistingJob(string jobName, SPWebApplication site)
    {
        bool jobDeleted = false;
        try
        {
            foreach (SPJobDefinition job in site.JobDefinitions)
            {
                if (job.Name == jobName)
                {
                    job.Delete();
                    jobDeleted = true;
                }
            }
        }
        catch (Exception)
        {
            return jobDeleted;
        }
        return jobDeleted;
    }
}
  1. 在网络应用上部署并激活您的功能(我认为最好是将作业配置为每天或每小时运行)

    • 一篇不错的文章,上面有一些示例,所有操作都可以在此处找到(我知道该文章适用于SP 2010,但它在2013、2016和2019年同样适用(使用此本地版本,我没有很多经验):)
    • 用相同的解决方案的另一篇文章在这里 (这对SP 2013)

**更新**

对于SharePoint Online,以上解决方案将无法使用,因为它是场解决方案。 在Online中,解决方案始终是“外部” :)。 当然,您已经拥有某种服务器,可以在线存储SP的解决方案(例如提供商托管的SP应用等)。 我的方法是开发一个简单的C#控制台应用程序。 首先在此应用程序中执行与mySql的SQL连接,并查询表以获取数据..然后使用CSOM查询SharePoint列表进行比较。 像这样的东西



    using (var clientContext = new ClientContext("url"))
    {
        CamlQuery camlQuery = new CamlQuery();
        string query = "add some query here";
        camlQuery.ViewXml = query;
        collListItem = list.GetItems(camlQuery);
        clientContext.Load(collListItem, items => items.Include( item => item["Title"], item => .... // add other columns You need here);
        clientContext.ExecuteQuery();

        if (collListItem.Count > 0)
        {
            // Your code here :)
        }
    } 

另外请注意,您可以使用其他用户的凭据(例如某种管理员)运行CSOM,并提供如下网络凭据:


NetworkCredential _myCredentials = new NetworkCredential("user", "password", "companydomain");

还请注意阈值...在CSOM中,您始终可以使用分页查询,在此之后您首先获得5000个项目,然后在5000个以下(以此类推),直到集合为空:)。 在手动运行了几次此控制台应用程序以确保其正常运行之后,只需将此控制台应用程序作为任务库中的新任务添加到此服务器上的Task Scheduler中即可。 您还可以在其中提供触发时间,例如每小时或每天运行等。 是一个不错的堆栈溢出信息,介绍如何添加此类任务

..我希望现在的答案对于您的环境更好:)

因此,我的C#程序取得了长足的进步。 我使用MySql.Data CSOM在MySql数据库和SharePoint在线之间具有功能齐全的连接。 可以操纵和控制内部的所有列表和数据。

但是,我有一个问题,不确定是否可以解决。 关于这个主题,我几乎找不到信息。

我创建一个新的ListItem。 将所有字段设置为一个值。 但是有一列是“ Person”类型的。 每个员工都有自己的网站链接到该网站,例如Lookup。 将值添加到该字段时,服务器给我以下错误:

Microsoft.SharePoint.Client.ServerException: Invalid data has been used to update the list item. The field you are trying to update may be read only.
   at Microsoft.SharePoint.Client.ClientRequest.ProcessResponseStream(Stream responseStream)
   at Microsoft.SharePoint.Client.ClientRequest.ProcessResponse()
   at Microsoft.SharePoint.Client.ClientRequest.ExecuteQueryToServer(ChunkStringBuilder sb)
   at Microsoft.SharePoint.Client.ClientContext.ExecuteQuery()
   at SPList.CreateNewItem(String userName, Int32 employeeNumber, String fullName, String firstName, String lastName, DateTime emplymentStart, DateTime employmentEnd, String department, String mobile, String address, String postcode, String postTown, String email) in C:\Users\fjs\source\repos\daily_CC_SP_update\SPList.cs:line 153

SharePoint字段规范

这是我创建新项目的代码。

using System;
using Microsoft.SharePoint.Client;
using System.Linq;
using System.Net;

public class SPList
{
    private readonly ClientContext context;
    private readonly List list;
    private readonly ListItemCollection items;
    private readonly Web web;

    //Credentials may be needed, its commented out!
    public SPList(String siteUrl, String listName, NetworkCredential netCred)
    {
        try
        {
            //NetworkCredential _myCredentials = netCred;
            context = new ClientContext(siteUrl);
            list = context.Web.Lists.GetByTitle(listName);
            items = list.GetItems(CamlQuery.CreateAllItemsQuery());
            web = context.Web;
            context.Load(items);
            context.Load(list);
            context.Load(context.Web.Lists, lists => lists.Include(list => list.Title));
            context.ExecuteQuery();
            Console.WriteLine("Connected to SharePoint successfully!");
        }
        catch(Exception e)
        {
            Console.WriteLine(e);
        }
    }

    public void CreateNewItem(String userName, int employeeNumber, String fullName, String firstName, String lastName, DateTime emplymentStart, DateTime employmentEnd, String department, String mobile, String address, String postcode, String postTown, String email)
    {
        try
        {
            ListItemCreationInformation newItemSepc = new ListItemCreationInformation();
            ListItem newItem = list.AddItem(newItemSepc);
            newItem["Title"] = userName;
            newItem["Employee_x0020_Number"] = employeeNumber;
            newItem["Full_x0020_Name"] = fullName;
            newItem["First_x0020_Name"] = firstName;
            newItem["Last_x0020_Name"] = lastName;
            newItem["_x000a_Employment_x0020_start_x0"] = emplymentStart.Date;
            newItem["Employment_x0020_end_x0020_date"] = employmentEnd.Date;
            newItem["Department"] = department;
            newItem["Mobile"] = mobile;
            newItem["Adress"] = address;
            newItem["Postcode"] = postcode;
            newItem["Post_x0020_town"] = postTown;
            newItem["Email"] = email;
            newItem["Person"] = fullName;
            newItem.Update();
            context.ExecuteQuery();
        }
        catch(Exception e)
        {
            Console.WriteLine(e);
        }
    }
}

如果我评论newItem [“ Person”] = fullName; 出来的代码工作正常。 可以解决这个问题吗? 否则,我必须在SharePoint中编辑该项目并添加值:/

奇怪的字段名称是因为SharePoint由于某种原因以这种方式存储它

解决方案是将items [“ LockUpColumn”]设置为字符串而不是锁定字段

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM