我在從我的數據實體創建業務實體時遇到了很多麻煩。使用自我導航屬性映射數據實體到業務實體
我Data.Entities.User如下所示:
public class User
{
public User()
{
Messages = new List<Message>();
Followers = new List<User>();
Favorites = new List<Message>();
Notifications = new List<Notification>();
SubscribedTopics = new List<Topic>();
}
public string Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Tag { get; set; }
public string Picture { get; set; }
public ICollection<Message> Messages { get; set; }
public ICollection<User> Followers { get; set; }
public ICollection<Message> Favorites { get; set; }
public ICollection<Notification> Notifications { get; set; }
public ICollection<Topic> SubscribedTopics { get; set; }
}
我Data.Mappers.UserMapper看起來是這樣的:
class UserMapper : EntityTypeConfiguration<User>
{
public UserMapper()
{
// Table Mapping
ToTable("Users");
// Primary Key
HasKey(u => u.Id);
Property(u => u.Id)
.IsRequired();
// Properties
Property(u => u.Name)
.IsRequired()
.HasMaxLength(140);
Property(u => u.Email)
.IsRequired()
.HasMaxLength(255)
.IsUnicode(false);
Property(u => u.Tag)
.IsRequired()
.IsUnicode(false)
.HasMaxLength(255)
.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute()));
Property(u => u.Picture)
.IsOptional();
// Relationships
HasMany(u => u.Followers)
.WithMany()
.Map(u => u.MapLeftKey("FollowerID"));
HasMany(u => u.Favorites)
.WithMany()
.Map(u => u.MapLeftKey("MessageID"));
HasMany(u => u.SubscribedTopics)
.WithMany(t => t.Subscribers)
.Map(u =>
{
u.ToTable("TopicSubscribers");
u.MapLeftKey("UserID");
u.MapRightKey("TopicID");
});
}
}
最後,我Domain.Entities.User這樣的:
public class User : EntityBase<string>
{
public string Name { get; set; }
public string Email { get; set; }
public string Tag { get; set; }
public string Picture { get; set; }
public IEnumerable<Message> Messages { get; set; }
public IEnumerable<User> Followers { get; set; }
public IEnumerable<Message> Favorites { get; set; }
public IEnumerable<Notification> Notifications { get; set; }
public IEnumerable<Topic> SubscribedTopics { get; set; }
protected override void Validate()
{
if (string.IsNullOrWhiteSpace(Name))
{
AddBrokenRule(new ValidationRule("Name", "Name_Missing"));
}
if (string.IsNullOrWhiteSpace(Email))
{
AddBrokenRule(new ValidationRule("Email", "Email_Missing"));
}
if (string.IsNullOrWhiteSpace(Tag))
{
AddBrokenRule(new ValidationRule("Tag", "Tag_Missing"));
}
System.Uri uriResult;
if (!string.IsNullOrWhiteSpace(Picture) &&
Uri.TryCreate(Picture, UriKind.Absolute, out uriResult) &&
(uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps))
{
AddBrokenRule(new ValidationRule("Picture", "Picture_InvalidURI"));
}
}
}
EntityBase將標識參數,所以就參數而言,這兩個類應該是相同的。
我遇到麻煩的部分是將數據實體映射到域實體。
public override IEnumerable<User> GetAll()
{
IEnumerable<User> user = _context.Users.Project()
.To<User>("Followers");
return user;
}
我認爲導致麻煩的是圓形導航屬性。 User1可能有一個名爲User2的追隨者,同時在User2之後。
到目前爲止,我曾經嘗試都AutoMapper和ValueInjecter,但我還沒有與任何任何成功。
- 我試着給所有導航屬性添加「虛擬」,啓用惰性和代理加載,但這會導致AutoMapper和ValueInjecter都失敗。 ValueInjecter由於已經打開的數據讀取器和AutoMapper,因爲類型不匹配。
- 我試過顯式加載導航屬性,但只要我在用戶包含(「關注」),我得到一個計算器。
- 試圖創建一個AutoMapperConfiguration,其中我指定maxDepth爲1會產生一個計算器,除非我將opt.ExplicitExpansion添加到每個導航屬性。
- 如果我再嘗試明確擴大導航財產,我得到
類型「ShortStuff.Domain.Entities.User」出現在兩個結構 不相容初始化一個單一的LINQ to Entities查詢中。 A 類型可以在同一個查詢中的兩個地方進行初始化,但只有在 兩個地方都設置了相同的屬性並且這些屬性是 以相同的順序設置。
理想情況下,我想要一個解決方案,讓我明確地控制哪些導航屬性擴展而無需遞歸。
例如,我想這樣做:
_context.Users.Include("Followers").NoNavigation().AsEnumerable();
然後,我將能夠訪問用戶。關注者並擁有其他用戶的列表,並將其導航屬性設置爲空。
非常感謝!我的存儲庫/服務學習項目的
完整的源代碼可以在Github在https://github.com/Bio2hazard/ShortStuff/tree/master/ShortStuffApi
編輯發現: 我取得了一些進展。
我得到的東西通過關閉代理生成&延遲加載,然後使用ValueInjector像這樣的工作:
IEnumerable<Data.Entities.User> userList = _context.Users.Include("Followers").Include("Favorites").Include("Messages").Include("Notifications").Include("SubscribedTopics");
IEnumerable<User> users = userList.Select(u => new User
{
Id = u.Id,
Email = u.Email,
Picture = u.Picture,
Tag = u.Tag,
Name = u.Name,
Followers = u.Followers.Select(uu => new User().InjectFrom<SmartConventionInjection>(uu)).Cast<User>(),
Favorites = u.Favorites.Select(uf => new Message().InjectFrom<SmartConventionInjection>(uf)).Cast<Message>(),
Messages = u.Messages.Select(um => new Message().InjectFrom<SmartConventionInjection>(um)).Cast<Message>(),
Notifications = u.Notifications.Select(un => new Notification().InjectFrom<SmartConventionInjection>(un)).Cast<Notification>(),
SubscribedTopics = u.SubscribedTopics.Select(ut => new Topic().InjectFrom<SmartConventionInjection>(ut)).Cast<Topic>()
});
但是,這是一噸的代碼。我可能可以爲此創建一個工廠,但必須有一個更簡單的方法,對吧?