我将如何在 sensenet 中实施公司简介?
How would I implement a company profile in sensenet?
当用户在我的网络应用程序中注册时,他们必须输入三项内容:他们的用户名、公司名称和密码。现在,我接下来要如何处理这些信息完全取决于我如何实施它。理想情况下,我希望用户有两个配置文件:用户和公司配置文件。 Sensenet 已经带有内置的用户配置文件并查看内容类型定义,这就是它的定义方式。
<?xml version="1.0" encoding="utf-8"?>
<ContentType name="UserProfile" parentType="Workspace" handler="SenseNet.ContentRepository.UserProfile" xmlns="http://schemas.sensenet.com/SenseNet/ContentRepository/ContentTypeDefinition">
<DisplayName>$Ctd-UserProfile,DisplayName</DisplayName>
<Description>$Ctd-UserProfile,Description</Description>
<Icon>UserProfile</Icon>
<AllowedChildTypes>
Blog,DocumentLibrary,EventList,MemoList,LinkList,TaskList,ImageLibrary,Posts,CustomList
</AllowedChildTypes>
<Fields>
<Field name="IsWallContainer" type="Boolean">
<Configuration>
<VisibleBrowse>Advanced</VisibleBrowse>
<VisibleEdit>Advanced</VisibleEdit>
<VisibleNew>Show</VisibleNew>
<DefaultValue>true</DefaultValue>
</Configuration>
</Field>
<Field name="IsCritical" type="Boolean">
<Configuration>
<VisibleBrowse>Hide</VisibleBrowse>
<VisibleEdit>Hide</VisibleEdit>
<VisibleNew>Hide</VisibleNew>
</Configuration>
</Field>
<Field name="Manager" type="Reference">
<Configuration>
<VisibleBrowse>Hide</VisibleBrowse>
<VisibleEdit>Hide</VisibleEdit>
<VisibleNew>Hide</VisibleNew>
</Configuration>
</Field>
<Field name="Deadline" type="DateTime">
<Configuration>
<VisibleBrowse>Hide</VisibleBrowse>
<VisibleEdit>Hide</VisibleEdit>
<VisibleNew>Hide</VisibleNew>
</Configuration>
</Field>
<Field name="IsActive" type="Boolean">
<Configuration>
<VisibleBrowse>Hide</VisibleBrowse>
<VisibleEdit>Hide</VisibleEdit>
<VisibleNew>Hide</VisibleNew>
</Configuration>
</Field>
<Field name="User" type="Reference">
<DisplayName>$Ctd-UserProfile,User-DisplayName</DisplayName>
<Configuration>
<AllowMultiple>false</AllowMultiple>
<AllowedTypes>
<Type>User</Type>
</AllowedTypes>
<SelectionRoot>
<Path>/Root/IMS</Path>
</SelectionRoot>
</Configuration>
</Field>
</Fields>
</ContentType>
引起我注意的是引用附加到用户配置文件的用户的引用字段。因此,有了这些知识,也许最好创建一个单独的内容类型定义,其中包含与此相同的引用字段,以便它与同一用户相关联。我可以走的另一个方向是扩展用户配置文件内容类型定义 xml 文件,将公司的信息嵌入其中,而不是为其单独定义文件,但问题是现在我要改变关于什么是用户个人资料,可能包含太多信息。
最重要的是,任何其他用户都不能绑定到同一家公司,因为它必须是唯一的。考虑到所有这些,您认为以下哪种方法是执行此操作的最佳方法?
编辑 1
所以我在为用户制作公司简介方面取得了一些进展。我为公司简介创建了这个内容处理程序。
using SenseNet.ContentRepository.Schema;
using SenseNet.ContentRepository.Storage;
using SenseNet.ContentRepository.Workspaces;
namespace DerAssistantService.ContentHandlers
{
[ContentHandler]
public class CompanyProfile : Workspace
{
public CompanyProfile(Node parent) : this(parent, null) { }
public CompanyProfile(Node parent, string nodeTypeName) : base(parent, nodeTypeName) { }
protected CompanyProfile(NodeToken nt) : base(nt) { }
public override string Name
{
get { return base.Name;}
set { base.Name = value;}
}
[RepositoryProperty("Address")]
public string Address
{
get { return GetProperty<string>("Address"); }
set { this["Address"] = value; }
}
[RepositoryProperty("City")]
public string City
{
get { return GetProperty<string>("City"); }
set { this["City"] = value; }
}
[RepositoryProperty("State")]
public string State
{
get { return GetProperty<string>("State"); }
set { this["State"] = value; }
}
public override object GetProperty(string name)
{
switch (name)
{
case "Address":
return Address;
case "City":
return City;
case "State":
return State;
default:
return base.GetProperty(name);
}
}
public override void SetProperty(string name, object value)
{
switch (name)
{
case "Address":
Address = (string)value;
break;
case "City":
City = (string)value;
break;
case "State":
State = (string)value;
break;
default:
base.SetProperty(name, value);
break;
}
}
}
}
他们注册时,会在公司域下创建公司资料。
using System;
using System.Linq;
using SenseNet.ApplicationModel;
using SenseNet.ContentRepository;
using SenseNet.ContentRepository.Storage;
using SenseNet.ContentRepository.Storage.Data;
using SenseNet.ContentRepository.Storage.Security;
namespace DerAssistantService.Actions
{
public static class UserActions
{
[ODataAction]
public static Content RegisterUser(Content content, string email, string companyname, string password)
{
if (string.IsNullOrEmpty(email))
throw new ArgumentNullException(nameof(email));
if (string.IsNullOrEmpty(companyname))
throw new ArgumentNullException(nameof(companyname));
if (string.IsNullOrEmpty(password))
throw new ArgumentNullException(nameof(password));
var username = email.Split('@').First();
var isUserCreated = Node.LoadNode("Root/IMS/Public/" + username);
var isCompanyProfileCreated = Node.LoadNode("Root/Profiles/Company" + companyname);
if (isUserCreated != null)
{
throw new NodeAlreadyExistsException("There already exists a user with this name.");
}
if (isCompanyProfileCreated != null)
{
throw new NodeAlreadyExistsException("There already exists a company with this name.");
}
using (new SystemAccount())
{
var user = Content.CreateNew("User", content.ContentHandler, username);
user["FullName"] = username;
user["Email"] = email;
user["LoginName"] = email;
user["Enabled"] = true;
user["Password"] = password;
user.Save();
var parent = Node.LoadNode("Root/Profiles/Company");
var companyProfile = Content.CreateNew("CompanyProfile", parent, companyname);
companyProfile["Name"] = companyname;
companyProfile.Save();
var identifiedUsers = Node.Load<Group>("/Root/IMS/BuiltIn/Portal/IdentifiedUsers");
identifiedUsers.AddMember(user.ContentHandler as IUser);
identifiedUsers.Save();
return user;
}
}
}
}
我为它创建了这个内容类型定义。
<ContentType name="CompanyProfile" parentType="Workspace" handler="DerAssistantService.ContentHandlers.CompanyProfile" xmlns="http://schemas.sensenet.com/SenseNet/ContentRepository/ContentTypeDefinition">
<DisplayName>CompanyProfile</DisplayName>
<Description>This content contains basic information on a company</Description>
<Icon>Company</Icon>
<Fields>
<Field name="Name" type="ShortText">
<DisplayName>Company</DisplayName>
<Description>The name of the company</Description>
<Configuration>
<VisibleBrowse>Show</VisibleBrowse>
<VisibleEdit>Show</VisibleEdit>
<VisibleNew>Show</VisibleNew>
<Compulsory>true</Compulsory>
</Configuration>
</Field>
<Field name="Address" type="ShortText">
<DisplayName>Address</DisplayName>
<Description>The location of the company</Description>
<Configuration>
<VisibleBrowse>Show</VisibleBrowse>
<VisibleEdit>Show</VisibleEdit>
<VisibleNew>Show</VisibleNew>
<Compulsory>true</Compulsory>
</Configuration>
</Field>
<Field name="City" type="ShortText">
<DisplayName>City</DisplayName>
<Description>The city where the company is located at</Description>
<Configuration>
<VisibleBrowse>Show</VisibleBrowse>
<VisibleEdit>Show</VisibleEdit>
<VisibleNew>Show</VisibleNew>
<Compulsory>true</Compulsory>
</Configuration>
</Field>
<Field name="State" type="ShortText">
<DisplayName>State</DisplayName>
<Description>The state the company resides in</Description>
<Configuration>
<VisibleBrowse>Show</VisibleBrowse>
<VisibleEdit>Show</VisibleEdit>
<VisibleNew>Show</VisibleNew>
<Compulsory>true</Compulsory>
</Configuration>
</Field>
</Fields>
</ContentType>
问题,我无法轻松加载公司资料。两者之间没有联系,因为两者都在不同的域中,彼此之间没有任何信息。我该如何协调?
编辑 2
经过一些实验,我终于有了一个可行的解决方案。
这是我的公司资料现在的样子。
<?xml version="1.0" encoding="utf-8"?>
<ContentType name="CompanyProfile" parentType="UserProfile" handler="DerAssistantService.ContentHandlers.CompanyProfile" xmlns="http://schemas.sensenet.com/SenseNet/ContentRepository/ContentTypeDefinition">
<DisplayName>CompanyProfile</DisplayName>
<Description>This profile contains contains a single reference to a company that has registered itself in the web app.</Description>
<Icon>UserProfile</Icon>
<AllowedChildTypes>DocumentLibrary,EventList,MemoList,LinkList,TaskList,ImageLibrary,CustomList</AllowedChildTypes>
<Fields>
<Field name="Company" type="Reference">
<DisplayName>Company</DisplayName>
<Configuration>
<AllowMultiple>false</AllowMultiple>
<AllowedTypes>
<Type>Company</Type>
</AllowedTypes>
<SelectionRoot>
<Path>/Root/IMS</Path>
</SelectionRoot>
</Configuration>
</Field>
</Fields>
</ContentType>
现在公司资料扩展了用户资料,这样我仍然有一个对用户对象的引用,并且有一个新的公司对象引用 属性。
现在我有一个公司的单独内容类型定义文件。
<?xml version="1.0" encoding="utf-8"?>
<ContentType name="Company" parentType="Workspace" handler="DerAssistantService.ContentHandlers.Company" xmlns="http://schemas.sensenet.com/SenseNet/ContentRepository/ContentTypeDefinition">
<DisplayName>Company</DisplayName>
<Description>This content contains basic information on a particular company</Description>
<Icon>Company</Icon>
<AllowedChildTypes>Image</AllowedChildTypes>
<Fields>
<Field name="Address" type="ShortText">
<DisplayName>Address</DisplayName>
<Description>The location of the company</Description>
<Configuration>
<VisibleBrowse>Show</VisibleBrowse>
<VisibleEdit>Show</VisibleEdit>
<VisibleNew>Show</VisibleNew>
<Compulsory>true</Compulsory>
</Configuration>
</Field>
<Field name="City" type="ShortText">
<DisplayName>City</DisplayName>
<Description>The city where the company resides in</Description>
<Configuration>
<VisibleBrowse>Show</VisibleBrowse>
<VisibleEdit>Show</VisibleEdit>
<VisibleNew>Show</VisibleNew>
<Compulsory>true</Compulsory>
</Configuration>
</Field>
<Field name="State" type="ShortText">
<DisplayName>State</DisplayName>
<Description>The state the company resides in</Description>
<Configuration>
<VisibleBrowse>Show</VisibleBrowse>
<VisibleEdit>Show</VisibleEdit>
<VisibleNew>Show</VisibleNew>
<Compulsory>true</Compulsory>
</Configuration>
</Field>
</Fields>
</ContentType>
这是我的 CompanyProfile 内容处理程序的样子
using SenseNet.ContentRepository;
using SenseNet.ContentRepository.Schema;
using SenseNet.ContentRepository.Storage;
namespace DerAssistantService.ContentHandlers
{
[ContentHandler]
public class CompanyProfile : UserProfile
{
public CompanyProfile(Node parent) : this(parent, null) { }
public CompanyProfile(Node parent, string nodeTypeName) : base(parent, nodeTypeName) { }
protected CompanyProfile(NodeToken token) : base(token) { }
[RepositoryProperty("Company", RepositoryDataType.Reference)]
public Company Company
{
get { return GetReference<Company>("Company"); }
set { SetReference("Company", value); }
}
public override object GetProperty(string name)
{
switch (name)
{
case "Company":
return Company;
default:
return base.GetProperty(name);
}
}
public override void SetProperty(string name, object value)
{
switch (name)
{
case "Company":
Company = (Company)value;
break;
default:
base.SetProperty(name, value);
break;
}
}
}
}
以及我公司 class 的内容处理程序是怎样的。
using SenseNet.ContentRepository.Schema;
using SenseNet.ContentRepository.Storage;
using SenseNet.ContentRepository.Workspaces;
namespace DerAssistantService.ContentHandlers
{
[ContentHandler]
public class Company : Workspace
{
public Company(Node parent) : this(parent, null) { }
public Company(Node parent, string nodeTypeName) : base(parent, nodeTypeName) { }
protected Company(NodeToken token) : base(token) { }
[RepositoryProperty("Address", RepositoryDataType.String)]
public string Address
{
get { return GetProperty<string>("Address"); }
set { this["Address"] = value; }
}
[RepositoryProperty("City", RepositoryDataType.String)]
public string City
{
get { return GetProperty<string>("City"); }
set { this["City"] = value; }
}
[RepositoryProperty("State", RepositoryDataType.String)]
public string State
{
get { return GetProperty<string>("State"); }
set { this["State"] = value; }
}
public override object GetProperty(string name)
{
switch (name)
{
case "Address":
return Address;
case "City":
return City;
case "State":
return State;
default:
return base.GetProperty(name);
}
}
public override void SetProperty(string name, object value)
{
switch (name)
{
case "Address":
Address = (string)value;
break;
case "City":
City = (string)value;
break;
case "State":
State = (string)value;
break;
default:
base.SetProperty(name, value);
break;
}
}
}
}
我在我的 RegisterUser 方法中分离了逻辑,因为它做的太多了。
我的 RegisterUser 函数现在看起来像这样。
[ODataAction]
public static Content RegisterUser(Content content, string email, string password)
{
using (new SystemAccount())
{
var username = email.Split('@').First();
var user = CreateUser("Public", email, password, username, true);
var identifiedUsers = Node.Load<Group>("/Root/IMS/BuiltIn/Portal/IdentifiedUsers");
identifiedUsers.AddMember(user.ContentHandler as IUser);
identifiedUsers.Save();
return user;
}
}
private static Content CreateUser(string domainName, string username, string password, string fullname, bool enabled, Dictionary<string, object> properties = null)
{
var domainPath = RepositoryPath.Combine(RepositoryStructure.ImsFolderPath, domainName);
var domain = Node.LoadNode(domainPath);
var user = Content.CreateNew("User", domain, username);
user["Name"] = username;
user["Password"] = password;
user["FullName"] = fullname;
user["Enabled"] = enabled;
if (properties != null)
{
foreach (var key in properties.Keys)
{
user[key] = properties[key];
}
}
user.Save();
return user;
}
}
我创建了一个单独的函数,负责在创建用户后注册公司,因为我需要创建用户对象,以便它可以创建公司资料。
[ODataAction]
public static Content RegisterCompany(Content content, string companyName, string userEmail)
{
using (new SystemAccount())
{
CompanyProfile companyProfile = Node.LoadNode("/Root/Profiles/Public/" + userEmail) as CompanyProfile;
Company company = CreateCompany(companyName, companyProfile);
var companyContent = Content.Create(company);
companyContent.Save();
companyProfile.Company = company;
companyProfile.Save();
return companyContent;
}
}
private static Company CreateCompany(string companyName, CompanyProfile companyProfile)
{
var parent = Node.LoadNode("/Root/IMS/Company");
Company company = new Company(parent);
company.Name = companyName;
company.Address = "N/A";
company.City = "N/A";
company.State = "N/A";
company.VersionCreatedBy = companyProfile.User;
company.VersionModifiedBy = companyProfile.User;
company.CreatedBy = companyProfile.User;
company.ModifiedBy = companyProfile.User;
company.Owner = companyProfile.User;
return company;
}
}
有了这个,如果我按顺序向 RegisterUser 和 RegisterCompany 发出请求,公司资料现在将具有对创建的公司对象的引用。请告诉我是否有任何其他方法可以重组它。
我认为你需要反转参考方向。例如,用户在一家公司工作,该公司可以有个人资料。因此,用户可以使用单个参考字段来定位公司或公司的资料。这种机制提供了双向的轻松访问:如果您有用户实例 user.Company
或 user.CompanyProfile
returns 目标对象。可以通过类似这样的简单查询访问向后方向:Content.All.OfType<User>().Where(c => c.Company == company).FirstOrDefault()
.
当用户在我的网络应用程序中注册时,他们必须输入三项内容:他们的用户名、公司名称和密码。现在,我接下来要如何处理这些信息完全取决于我如何实施它。理想情况下,我希望用户有两个配置文件:用户和公司配置文件。 Sensenet 已经带有内置的用户配置文件并查看内容类型定义,这就是它的定义方式。
<?xml version="1.0" encoding="utf-8"?>
<ContentType name="UserProfile" parentType="Workspace" handler="SenseNet.ContentRepository.UserProfile" xmlns="http://schemas.sensenet.com/SenseNet/ContentRepository/ContentTypeDefinition">
<DisplayName>$Ctd-UserProfile,DisplayName</DisplayName>
<Description>$Ctd-UserProfile,Description</Description>
<Icon>UserProfile</Icon>
<AllowedChildTypes>
Blog,DocumentLibrary,EventList,MemoList,LinkList,TaskList,ImageLibrary,Posts,CustomList
</AllowedChildTypes>
<Fields>
<Field name="IsWallContainer" type="Boolean">
<Configuration>
<VisibleBrowse>Advanced</VisibleBrowse>
<VisibleEdit>Advanced</VisibleEdit>
<VisibleNew>Show</VisibleNew>
<DefaultValue>true</DefaultValue>
</Configuration>
</Field>
<Field name="IsCritical" type="Boolean">
<Configuration>
<VisibleBrowse>Hide</VisibleBrowse>
<VisibleEdit>Hide</VisibleEdit>
<VisibleNew>Hide</VisibleNew>
</Configuration>
</Field>
<Field name="Manager" type="Reference">
<Configuration>
<VisibleBrowse>Hide</VisibleBrowse>
<VisibleEdit>Hide</VisibleEdit>
<VisibleNew>Hide</VisibleNew>
</Configuration>
</Field>
<Field name="Deadline" type="DateTime">
<Configuration>
<VisibleBrowse>Hide</VisibleBrowse>
<VisibleEdit>Hide</VisibleEdit>
<VisibleNew>Hide</VisibleNew>
</Configuration>
</Field>
<Field name="IsActive" type="Boolean">
<Configuration>
<VisibleBrowse>Hide</VisibleBrowse>
<VisibleEdit>Hide</VisibleEdit>
<VisibleNew>Hide</VisibleNew>
</Configuration>
</Field>
<Field name="User" type="Reference">
<DisplayName>$Ctd-UserProfile,User-DisplayName</DisplayName>
<Configuration>
<AllowMultiple>false</AllowMultiple>
<AllowedTypes>
<Type>User</Type>
</AllowedTypes>
<SelectionRoot>
<Path>/Root/IMS</Path>
</SelectionRoot>
</Configuration>
</Field>
</Fields>
</ContentType>
引起我注意的是引用附加到用户配置文件的用户的引用字段。因此,有了这些知识,也许最好创建一个单独的内容类型定义,其中包含与此相同的引用字段,以便它与同一用户相关联。我可以走的另一个方向是扩展用户配置文件内容类型定义 xml 文件,将公司的信息嵌入其中,而不是为其单独定义文件,但问题是现在我要改变关于什么是用户个人资料,可能包含太多信息。
最重要的是,任何其他用户都不能绑定到同一家公司,因为它必须是唯一的。考虑到所有这些,您认为以下哪种方法是执行此操作的最佳方法?
编辑 1
所以我在为用户制作公司简介方面取得了一些进展。我为公司简介创建了这个内容处理程序。
using SenseNet.ContentRepository.Schema;
using SenseNet.ContentRepository.Storage;
using SenseNet.ContentRepository.Workspaces;
namespace DerAssistantService.ContentHandlers
{
[ContentHandler]
public class CompanyProfile : Workspace
{
public CompanyProfile(Node parent) : this(parent, null) { }
public CompanyProfile(Node parent, string nodeTypeName) : base(parent, nodeTypeName) { }
protected CompanyProfile(NodeToken nt) : base(nt) { }
public override string Name
{
get { return base.Name;}
set { base.Name = value;}
}
[RepositoryProperty("Address")]
public string Address
{
get { return GetProperty<string>("Address"); }
set { this["Address"] = value; }
}
[RepositoryProperty("City")]
public string City
{
get { return GetProperty<string>("City"); }
set { this["City"] = value; }
}
[RepositoryProperty("State")]
public string State
{
get { return GetProperty<string>("State"); }
set { this["State"] = value; }
}
public override object GetProperty(string name)
{
switch (name)
{
case "Address":
return Address;
case "City":
return City;
case "State":
return State;
default:
return base.GetProperty(name);
}
}
public override void SetProperty(string name, object value)
{
switch (name)
{
case "Address":
Address = (string)value;
break;
case "City":
City = (string)value;
break;
case "State":
State = (string)value;
break;
default:
base.SetProperty(name, value);
break;
}
}
}
}
他们注册时,会在公司域下创建公司资料。
using System;
using System.Linq;
using SenseNet.ApplicationModel;
using SenseNet.ContentRepository;
using SenseNet.ContentRepository.Storage;
using SenseNet.ContentRepository.Storage.Data;
using SenseNet.ContentRepository.Storage.Security;
namespace DerAssistantService.Actions
{
public static class UserActions
{
[ODataAction]
public static Content RegisterUser(Content content, string email, string companyname, string password)
{
if (string.IsNullOrEmpty(email))
throw new ArgumentNullException(nameof(email));
if (string.IsNullOrEmpty(companyname))
throw new ArgumentNullException(nameof(companyname));
if (string.IsNullOrEmpty(password))
throw new ArgumentNullException(nameof(password));
var username = email.Split('@').First();
var isUserCreated = Node.LoadNode("Root/IMS/Public/" + username);
var isCompanyProfileCreated = Node.LoadNode("Root/Profiles/Company" + companyname);
if (isUserCreated != null)
{
throw new NodeAlreadyExistsException("There already exists a user with this name.");
}
if (isCompanyProfileCreated != null)
{
throw new NodeAlreadyExistsException("There already exists a company with this name.");
}
using (new SystemAccount())
{
var user = Content.CreateNew("User", content.ContentHandler, username);
user["FullName"] = username;
user["Email"] = email;
user["LoginName"] = email;
user["Enabled"] = true;
user["Password"] = password;
user.Save();
var parent = Node.LoadNode("Root/Profiles/Company");
var companyProfile = Content.CreateNew("CompanyProfile", parent, companyname);
companyProfile["Name"] = companyname;
companyProfile.Save();
var identifiedUsers = Node.Load<Group>("/Root/IMS/BuiltIn/Portal/IdentifiedUsers");
identifiedUsers.AddMember(user.ContentHandler as IUser);
identifiedUsers.Save();
return user;
}
}
}
}
我为它创建了这个内容类型定义。
<ContentType name="CompanyProfile" parentType="Workspace" handler="DerAssistantService.ContentHandlers.CompanyProfile" xmlns="http://schemas.sensenet.com/SenseNet/ContentRepository/ContentTypeDefinition">
<DisplayName>CompanyProfile</DisplayName>
<Description>This content contains basic information on a company</Description>
<Icon>Company</Icon>
<Fields>
<Field name="Name" type="ShortText">
<DisplayName>Company</DisplayName>
<Description>The name of the company</Description>
<Configuration>
<VisibleBrowse>Show</VisibleBrowse>
<VisibleEdit>Show</VisibleEdit>
<VisibleNew>Show</VisibleNew>
<Compulsory>true</Compulsory>
</Configuration>
</Field>
<Field name="Address" type="ShortText">
<DisplayName>Address</DisplayName>
<Description>The location of the company</Description>
<Configuration>
<VisibleBrowse>Show</VisibleBrowse>
<VisibleEdit>Show</VisibleEdit>
<VisibleNew>Show</VisibleNew>
<Compulsory>true</Compulsory>
</Configuration>
</Field>
<Field name="City" type="ShortText">
<DisplayName>City</DisplayName>
<Description>The city where the company is located at</Description>
<Configuration>
<VisibleBrowse>Show</VisibleBrowse>
<VisibleEdit>Show</VisibleEdit>
<VisibleNew>Show</VisibleNew>
<Compulsory>true</Compulsory>
</Configuration>
</Field>
<Field name="State" type="ShortText">
<DisplayName>State</DisplayName>
<Description>The state the company resides in</Description>
<Configuration>
<VisibleBrowse>Show</VisibleBrowse>
<VisibleEdit>Show</VisibleEdit>
<VisibleNew>Show</VisibleNew>
<Compulsory>true</Compulsory>
</Configuration>
</Field>
</Fields>
</ContentType>
问题,我无法轻松加载公司资料。两者之间没有联系,因为两者都在不同的域中,彼此之间没有任何信息。我该如何协调?
编辑 2
经过一些实验,我终于有了一个可行的解决方案。
这是我的公司资料现在的样子。
<?xml version="1.0" encoding="utf-8"?>
<ContentType name="CompanyProfile" parentType="UserProfile" handler="DerAssistantService.ContentHandlers.CompanyProfile" xmlns="http://schemas.sensenet.com/SenseNet/ContentRepository/ContentTypeDefinition">
<DisplayName>CompanyProfile</DisplayName>
<Description>This profile contains contains a single reference to a company that has registered itself in the web app.</Description>
<Icon>UserProfile</Icon>
<AllowedChildTypes>DocumentLibrary,EventList,MemoList,LinkList,TaskList,ImageLibrary,CustomList</AllowedChildTypes>
<Fields>
<Field name="Company" type="Reference">
<DisplayName>Company</DisplayName>
<Configuration>
<AllowMultiple>false</AllowMultiple>
<AllowedTypes>
<Type>Company</Type>
</AllowedTypes>
<SelectionRoot>
<Path>/Root/IMS</Path>
</SelectionRoot>
</Configuration>
</Field>
</Fields>
</ContentType>
现在公司资料扩展了用户资料,这样我仍然有一个对用户对象的引用,并且有一个新的公司对象引用 属性。
现在我有一个公司的单独内容类型定义文件。
<?xml version="1.0" encoding="utf-8"?>
<ContentType name="Company" parentType="Workspace" handler="DerAssistantService.ContentHandlers.Company" xmlns="http://schemas.sensenet.com/SenseNet/ContentRepository/ContentTypeDefinition">
<DisplayName>Company</DisplayName>
<Description>This content contains basic information on a particular company</Description>
<Icon>Company</Icon>
<AllowedChildTypes>Image</AllowedChildTypes>
<Fields>
<Field name="Address" type="ShortText">
<DisplayName>Address</DisplayName>
<Description>The location of the company</Description>
<Configuration>
<VisibleBrowse>Show</VisibleBrowse>
<VisibleEdit>Show</VisibleEdit>
<VisibleNew>Show</VisibleNew>
<Compulsory>true</Compulsory>
</Configuration>
</Field>
<Field name="City" type="ShortText">
<DisplayName>City</DisplayName>
<Description>The city where the company resides in</Description>
<Configuration>
<VisibleBrowse>Show</VisibleBrowse>
<VisibleEdit>Show</VisibleEdit>
<VisibleNew>Show</VisibleNew>
<Compulsory>true</Compulsory>
</Configuration>
</Field>
<Field name="State" type="ShortText">
<DisplayName>State</DisplayName>
<Description>The state the company resides in</Description>
<Configuration>
<VisibleBrowse>Show</VisibleBrowse>
<VisibleEdit>Show</VisibleEdit>
<VisibleNew>Show</VisibleNew>
<Compulsory>true</Compulsory>
</Configuration>
</Field>
</Fields>
</ContentType>
这是我的 CompanyProfile 内容处理程序的样子
using SenseNet.ContentRepository;
using SenseNet.ContentRepository.Schema;
using SenseNet.ContentRepository.Storage;
namespace DerAssistantService.ContentHandlers
{
[ContentHandler]
public class CompanyProfile : UserProfile
{
public CompanyProfile(Node parent) : this(parent, null) { }
public CompanyProfile(Node parent, string nodeTypeName) : base(parent, nodeTypeName) { }
protected CompanyProfile(NodeToken token) : base(token) { }
[RepositoryProperty("Company", RepositoryDataType.Reference)]
public Company Company
{
get { return GetReference<Company>("Company"); }
set { SetReference("Company", value); }
}
public override object GetProperty(string name)
{
switch (name)
{
case "Company":
return Company;
default:
return base.GetProperty(name);
}
}
public override void SetProperty(string name, object value)
{
switch (name)
{
case "Company":
Company = (Company)value;
break;
default:
base.SetProperty(name, value);
break;
}
}
}
}
以及我公司 class 的内容处理程序是怎样的。
using SenseNet.ContentRepository.Schema;
using SenseNet.ContentRepository.Storage;
using SenseNet.ContentRepository.Workspaces;
namespace DerAssistantService.ContentHandlers
{
[ContentHandler]
public class Company : Workspace
{
public Company(Node parent) : this(parent, null) { }
public Company(Node parent, string nodeTypeName) : base(parent, nodeTypeName) { }
protected Company(NodeToken token) : base(token) { }
[RepositoryProperty("Address", RepositoryDataType.String)]
public string Address
{
get { return GetProperty<string>("Address"); }
set { this["Address"] = value; }
}
[RepositoryProperty("City", RepositoryDataType.String)]
public string City
{
get { return GetProperty<string>("City"); }
set { this["City"] = value; }
}
[RepositoryProperty("State", RepositoryDataType.String)]
public string State
{
get { return GetProperty<string>("State"); }
set { this["State"] = value; }
}
public override object GetProperty(string name)
{
switch (name)
{
case "Address":
return Address;
case "City":
return City;
case "State":
return State;
default:
return base.GetProperty(name);
}
}
public override void SetProperty(string name, object value)
{
switch (name)
{
case "Address":
Address = (string)value;
break;
case "City":
City = (string)value;
break;
case "State":
State = (string)value;
break;
default:
base.SetProperty(name, value);
break;
}
}
}
}
我在我的 RegisterUser 方法中分离了逻辑,因为它做的太多了。
我的 RegisterUser 函数现在看起来像这样。
[ODataAction]
public static Content RegisterUser(Content content, string email, string password)
{
using (new SystemAccount())
{
var username = email.Split('@').First();
var user = CreateUser("Public", email, password, username, true);
var identifiedUsers = Node.Load<Group>("/Root/IMS/BuiltIn/Portal/IdentifiedUsers");
identifiedUsers.AddMember(user.ContentHandler as IUser);
identifiedUsers.Save();
return user;
}
}
private static Content CreateUser(string domainName, string username, string password, string fullname, bool enabled, Dictionary<string, object> properties = null)
{
var domainPath = RepositoryPath.Combine(RepositoryStructure.ImsFolderPath, domainName);
var domain = Node.LoadNode(domainPath);
var user = Content.CreateNew("User", domain, username);
user["Name"] = username;
user["Password"] = password;
user["FullName"] = fullname;
user["Enabled"] = enabled;
if (properties != null)
{
foreach (var key in properties.Keys)
{
user[key] = properties[key];
}
}
user.Save();
return user;
}
}
我创建了一个单独的函数,负责在创建用户后注册公司,因为我需要创建用户对象,以便它可以创建公司资料。
[ODataAction]
public static Content RegisterCompany(Content content, string companyName, string userEmail)
{
using (new SystemAccount())
{
CompanyProfile companyProfile = Node.LoadNode("/Root/Profiles/Public/" + userEmail) as CompanyProfile;
Company company = CreateCompany(companyName, companyProfile);
var companyContent = Content.Create(company);
companyContent.Save();
companyProfile.Company = company;
companyProfile.Save();
return companyContent;
}
}
private static Company CreateCompany(string companyName, CompanyProfile companyProfile)
{
var parent = Node.LoadNode("/Root/IMS/Company");
Company company = new Company(parent);
company.Name = companyName;
company.Address = "N/A";
company.City = "N/A";
company.State = "N/A";
company.VersionCreatedBy = companyProfile.User;
company.VersionModifiedBy = companyProfile.User;
company.CreatedBy = companyProfile.User;
company.ModifiedBy = companyProfile.User;
company.Owner = companyProfile.User;
return company;
}
}
有了这个,如果我按顺序向 RegisterUser 和 RegisterCompany 发出请求,公司资料现在将具有对创建的公司对象的引用。请告诉我是否有任何其他方法可以重组它。
我认为你需要反转参考方向。例如,用户在一家公司工作,该公司可以有个人资料。因此,用户可以使用单个参考字段来定位公司或公司的资料。这种机制提供了双向的轻松访问:如果您有用户实例 user.Company
或 user.CompanyProfile
returns 目标对象。可以通过类似这样的简单查询访问向后方向:Content.All.OfType<User>().Where(c => c.Company == company).FirstOrDefault()
.