рдЬрдм DDD рдХреЛ рд╕рдордЭрдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдЖрдк рдЗрд╕ рдкреИрдЯрд░реНрди рдХреЗ рдкрд╛рд░ рдЖрдиреЗ рдХреА рд╕рдВрднрд╛рд╡рдирд╛ рд░рдЦрддреЗ рд╣реИрдВ, рдЬрд┐рд╕реЗ рдЕрдХреНрд╕рд░ рдПрдХ рджреВрд╕рд░реЗ рдХреЗ рд╕рд╛рде рдорд┐рд▓рдХрд░ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдХреЛрдИ рдХрдо рджрд┐рд▓рдЪрд╕реНрдк, рд░рд┐рдкреЛрдЬрд┐рдЯрд░реА рдкреИрдЯрд░реНрди рдирд╣реАрдВред рдпрд╣ рдкреИрдЯрд░реНрди рд╡реНрдпрд╛рд╡рд╕рд╛рдпрд┐рдХ рд╡рд╕реНрддреБрдУрдВ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХрддрд╛рдУрдВ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ, рдФрд░ рдлрд┐рд░ рдкреНрд░рд╢реНрдиреЛрдВ рдХреЛ рджреЛрд╣рд░рд╛рдП рдмрд┐рдирд╛ рдлрд╝рд┐рд▓реНрдЯрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП (рдФрд░ рдЙрдирдХреА рд░рдЪрдирд╛рдУрдВ) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред
рдЙрджрд╛рд╣рд░рдг
рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЪрд▓реЛ рд╕рд╛рдзрд╛рд░рдг рд╕рдореВрд╣ рдЪреИрдЯ рдХреЗ рд▓рд┐рдП рдПрдХ рдбреЛрдореЗрди рдбрд┐рдЬрд╝рд╛рдЗрди рдХрд░рддреЗ рд╣реИрдВ: рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рддреАрди рд╕рдВрд╕реНрдерд╛рдПрдБ рд╣реЛрдВрдЧреА: рд╕рдореВрд╣ рдФрд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛, рдЬрд┐рдирдХреЗ рдмреАрдЪ рдХрдИ-рд╕реЗ-рдХрдИ рд╕рдВрдмрдВрдз рд╣реИрдВ (рдПрдХ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╡рд┐рднрд┐рдиреНрди рд╕рдореВрд╣реЛрдВ рдореЗрдВ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рдПрдХ рд╕рдореВрд╣ рдореЗрдВ рдХрдИ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ) рдФрд░ рд╕рдВрджреЗрд╢ рдХрд╛ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдХрд░рдиреЗ рд╡рд╛рд▓рд╛ рд╕рдВрджреЗрд╢, рдЬрд┐рд╕реЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХрд┐рд╕реА рднреА рд╕рдореВрд╣ рдореЗрдВ рд▓рд┐рдЦ рд╕рдХрддрд╛ рд╣реИ:
public class Member { public string Nick { get; set; } public string Country { get; set; } public int Age { get; set; } public ICollection<Group> Groups { get; set; } public ICollection<Message> Messages { get; set; } } public class Message { public string Body { get; set; } public DateTime Timestamp { get; set; } public Member Author { get; set; } } public class Group { public string Name { get; set; } public string Subject { get; set; } public Member Owner { get; set; } public ICollection<Message> Messages { get; set; } public ICollection<Member> Members { get; set; } }
рдЕрдм рдХрд▓реНрдкрдирд╛ рдХрд░реЗрдВ рдХрд┐ рдЖрдк рдЕрдиреБрдкреНрд░рдпреЛрдЧ рд╕реЗрд╡рд╛ рдореЗрдВ рджреЛ рддрд░реАрдХреЗ рд▓рд┐рдЦ рд░рд╣реЗ рд╣реИрдВ:
/// <summary> /// , /// </summary> public ICollection<Member> GetMembersInGroupFromCountry(string groupName, string country) { } /// <summary> /// , /// </summary> public ICollection<Member> GetInactiveMembersInGroupOnDateRange(string groupName, DateTime start, DateTime end) { }
рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди 1 (рдЦрд░рд╛рдм):
рдЖрдк рд╕реЗрд╡рд╛рдУрдВ рдХреЛ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХреЗ рд╢реАрд░реНрд╖ рдкрд░ рд╕реНрд╡рдпрдВ рдкреНрд░рд╢реНрдиреЛрдВ рдХрд╛ рдирд┐рд░реНрдорд╛рдг рдХрд░рдиреЗ рджреЗ рд╕рдХрддреЗ рд╣реИрдВ:
public ICollection<Member> GetMembersInGroupFromCountry(string groupName, string country) { return _membersRepository.Query.Where(m => m.Groups.Any(g => g.Name == groupName) && m.Country == country); } public ICollection<Member> GetInactiveMembersInGroupOnDateRange(string groupName, DateTime start, DateTime end) { return _membersRepository.Query.Where(m => m.Groups.Any(g => g.Name == groupName) && !m.Messages.Any(msg => msg.Timestamp > start && msg.Timestamp < end)); }
рд╡рд┐рдкрдХреНрд╖:рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХреЗ рд▓рд┐рдП рдЕрдиреБрд░реЛрдз рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рдмрд╛рд╣рд░ рдХреА рдУрд░ рдЦреЛрд▓рдирд╛ рдЦрд░реАрджрд╛рд░реЛрдВ рд╕реЗ рд▓рд╛рдЗрд╕реЗрдВрд╕ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреЗ рдмрд┐рдирд╛ рдПрдХ рд╣рдерд┐рдпрд╛рд░ рдЯреНрд░реЗрдбрд┐рдВрдЧ рд╕реНрдЯреЛрд░ рдЦреЛрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рддреБрд▓рдиреАрдп рд╣реИ - рдЖрдк рдмрд╕ рд╕рднреА рдХрд╛ рдзреНрдпрд╛рди рдирд╣реАрдВ рд░рдЦреЗрдВрдЧреЗ рдФрд░ рдХреЛрдИ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдХрд┐рд╕реА рдХреЛ рдЧреЛрд▓реА рдорд╛рд░ рджреЗрдЧрд╛ред рд╕рд╛рджреГрд╢реНрдп рдХреЛ рд╕рдордЭрдиреЗ рджреЛ: рдЖрдк рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рд╕реЗрд╡рд╛ рдХреЗ рд╡рд┐рднрд┐рдиреНрди рднрд╛рдЧреЛрдВ рдореЗрдВ рдХреНрд╡реЗрд░реА рдХреЗ рд╢реАрд░реНрд╖ рдкрд░ рд╕рдорд╛рди рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рдмрд╣реБрдд рд╕рд╛рд░реЗ рд╣реЛрдВрдЧреЗ (рдпрджрд┐ рдЖрдк рдПрдХ рдирдпрд╛ рдлрд╝реАрд▓реНрдб рдЬреЛрдбрд╝рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓реЗрддреЗ рд╣реИрдВ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, IsDeleted рд╡рд┐рд╢реЗрд╖рддрд╛ рджреНрд╡рд╛рд░рд╛ рд╕рдореВрд╣реЛрдВ рдХреЛ рдлрд╝рд┐рд▓реНрдЯрд░ рдХрд░реЗрдВ, рдФрд░ IsBanned рд╡рд┐рд╢реЗрд╖рддрд╛ рджреНрд╡рд╛рд░рд╛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ) рдФрд░ рдХрдИ рдХреЗ рд▓рд┐рдП рдЗрд╕ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВред рдирдореВрдиреЗ - рдЖрдк рдПрдХ рд╡рд┐рдзрд┐ рдХреЛ рдпрд╛рдж рдХрд░рдиреЗ рдХрд╛ рдЬреЛрдЦрд┐рдо рдЪрд▓рд╛рддреЗ рд╣реИрдВред
рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди 2 (рдмреБрд░рд╛ рдирд╣реАрдВ):
рдЖрдк рдЖрд╕рд╛рдиреА рд╕реЗ рдЙрди рд╕рднреА рддрд░реАрдХреЛрдВ рдХрд╛ рд╡рд░реНрдгрди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЬрд┐рдирдореЗрдВ рдЙрди рд╕рднреА рддрд░реАрдХреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрддрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдЬрд┐рдиреНрд╣реЗрдВ рдлрд╝рд┐рд▓реНрдЯрд░ рдХрд░рдХреЗ рдЫреБрдкрд╛рдХрд░ рд╕реЗрд╡рд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдЗрд╕ рдкреНрд░рдХрд╛рд░ рд╣реЛрдЧрд╛:
public ICollection<Member> GetMembersInGroupFromCountry(string groupName, string country) { return _membersRepository. GetMembersInGroupFromCountry(groupName, country); } public ICollection<Member> GetInactiveMembersInGroupOnDateRange(string groupName, DateTime start, DateTime end) { return _membersRepository. GetInactiveMembersInGroupOnDateRange(groupName, start, end); }
рд╡рд┐рдкрдХреНрд╖:рдпрд╣ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдкрд╣рд▓реЗ рдХреА рдХрдорд┐рдпреЛрдВ рд╕реЗ рдореБрдХреНрдд рд╣реИ, рд▓реЗрдХрд┐рди рдЗрд╕рдХрд╛ рдЕрдкрдирд╛ рд╣реИ - рдзреАрд░реЗ-рдзреАрд░реЗ рдЖрдкрдХрд╛ рднрдВрдбрд╛рд░ рдмрдврд╝реЗрдЧрд╛ рдФрд░ рдкреНрд░рдлреБрд▓реНрд▓рд┐рдд рд╣реЛрдЧрд╛, рдФрд░ рдЕрдВрдд рдореЗрдВ, рдХреБрдЫ рдХрдордЬреЛрд░ рд░реВрдк рд╕реЗ рд╕рдорд░реНрдерд┐рдд рдореЗрдВ рдмрджрд▓ рдЬрд╛рдПрдЧрд╛ред
рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди 3 (рдЙрддреНрдХреГрд╖реНрдЯ):
рдпрд╣рд╛рдВ, рд╡рд┐рдирд┐рд░реНрджреЗрд╢ рдкреИрдЯрд░реНрди рдмрдЪрд╛рд╡ рдХреЗ рд▓рд┐рдП рдЖрддрд╛ рд╣реИ, рдзрдиреНрдпрд╡рд╛рдж рдЬрд┐рд╕рд╕реЗ рд╣рдорд╛рд░рд╛ рдХреЛрдб рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрд╛рдИ рджреЗрдЧрд╛:
public ICollection<Member> GetMembersInGroupFromCountry(string groupName, string country) { return _membersRepository.AllMatching(MemberSpecifications.Group(groupName) && MemberSpecs.FromCountry(country)); } public ICollection<Member> GetInactiveMembersInGroupOnDateRange(string groupName, DateTime start, DateTime end) { return _membersRepository.AllMatching(MemberSpecifications.Group(groupName) && MemberSpecs.InactiveInDateRange(start, end)); }
рд╣рдореЗрдВ рджреЛрд╣рд░рд╛ рд▓рд╛рдн рдорд┐рд▓рддрд╛ рд╣реИ: рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдПрдХ рдмрдЪреНрдЪреЗ рдХреЗ рдЖрдВрд╕реВ рдХреА рддрд░рд╣ рд╕рд╛рдл рд╣реЛрддреА рд╣реИ рдФрд░ рдкреНрд░рдлреБрд▓реНрд▓рд┐рдд рдирд╣реАрдВ рд╣реЛрддреА рд╣реИ, рдФрд░ рд╕реЗрд╡рд╛рдУрдВ рдореЗрдВ рдЕрдиреБрд░реЛрдзреЛрдВ рдХрд╛ рджреЛрд╣рд░рд╛рд╡ рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИ рдФрд░ рдХрд╣реАрдВ рди рдХрд╣реАрдВ рдХреЛрдИ рд╕рдорд╕реНрдпрд╛ рд╣реЛрдиреЗ рдХрд╛ рдЬреЛрдЦрд┐рдо рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрджрд┐ рдЖрдк IsDeleted рд╡рд┐рд╢реЗрд╖рддрд╛ рдХреЗ рджреНрд╡рд╛рд░рд╛ рд╣рд░ рдЬрдЧрд╣ рд╕рдореВрд╣реЛрдВ рдХреЛ рдлрд╝рд┐рд▓реНрдЯрд░ рдХрд░рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓реЗрддреЗ рд╣реИрдВ, рддреЛ рдЖрдкрдХреЛ рдХреЗрд╡рд▓ рдПрдХ рдмрд╛рд░ рдЗрд╕ рд╢рд░реНрдд рдХреЛ рдПрдХ рд╕рджрд╕реНрдпреАрдп рд╡рд┐рдирд┐рд░реНрджреЗрд╢ рдореЗрдВ рдЬреЛрдбрд╝рдирд╛ рд╣реЛрдЧрд╛ .FromGroup
рдкреИрдЯрд░реНрди рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
рдорд╛рд░реНрдЯрд┐рди рдлрд╛рдЙрд▓рд░ (рдФрд░ рдПрд░рд┐рдХ рдЗрд╡рд╛рдВрд╕) рдиреЗ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╡рд┐рдирд┐рд░реНрджреЗрд╢ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛ рдкреНрд░рд╕реНрддрд╛рд╡ рджрд┐рдпрд╛:
public abstract class Specification<T> { public abstract bool IsSatisfiedBy(T entity); }
Linqspecs.codeplex.com рдХреЗ рд▓реЛрдЧреЛрдВ рдиреЗ рдЗрд╕реЗ рдФрд░ рдЕрдзрд┐рдХ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА
рдлреНрд░реЗрдВрдбрд▓реА рдмрдирд╛рдпрд╛ (рдЗрд╕рдХреЗ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди EF, nHibernate, рдЗрддреНрдпрд╛рджрд┐ рдкрд░ рдЖрдзрд╛рд░рд┐рдд) рдФрд░ рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдзрд╛рд░рд╛рд╡рд╛рд╣рд┐рдХ:
public abstract class Specification<T> { public abstract Expression<Func<T, bool>> IsSatisfiedBy(); }
рдПрдХреНрд╕рдкреНрд░реЗрд╢рдирдЯреНрд░реА рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж, рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рдЗрд╕реЗ рдПрд╕рдХреНрдпреВрдПрд▓ рдпрд╛ рдХреБрдЫ рдФрд░ рдореЗрдВ рдЕрдиреБрд╡рд╛рдж рдХрд░ рд╕рдХрддрд╛ рд╣реИред рдореВрд▓ рддрд░реНрдХ рддрддреНрд╡реЛрдВ рдХреЗ рд╕рд╛рде рдореВрд▓ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:

рдЕрдм рд╣рдореЗрдВ рдмрд╕ рдПрдХ рд╕реНрдерд┐рд░ рд╡рд░реНрдЧ рд▓рд┐рдЦрдирд╛ рд╣реЛрдЧрд╛ рдЬрд┐рд╕рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рдЗрдХрд╛рдИ (рдХреБрд▓) рдХреЗ рд▓рд┐рдП рд╡рд┐рд╢рд┐рд╖реНрдЯрд┐рдпрд╛рдБ рд╣реЛрдВред рд╣рдорд╛рд░реЗ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрд╣ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦреЗрдЧрд╛:
public static class MemberSpecifications { public static Specification<Member> Group(string groupName) { return new DirectSpecification<User>(member => member.Groups.Any(g => g.Name == groupName)); } public static Specification<Member> Country(string country) { return new DirectSpecification<User>(member => member.Country == country); } public static Specification<Member> InactiveSinceTo(DateTime start, DateTime end) { return new DirectSpecification<User>(member => member.Messages.Any(msg => msg.Timestamp > start && msg.Timestamp < end)); } }
рдирд┐рд╖реНрдХрд░реНрд╖
рдпрд╣реА рдХрд╛рд░рдг рд╣реИ рдХрд┐ рд╣рдордиреЗ рдЕрдкрдиреЗ рдЫреЛрдЯреЗ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ рднреА рд╕реНрдерд┐рддрд┐рдпреЛрдВ рдХреЗ рджреЛрд╣рд░рд╛рд╡ рд╕реЗ рдЫреБрдЯрдХрд╛рд░рд╛ рдкрд╛ рд▓рд┐рдпрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЖрдк рдЬрдЯрд┐рд▓ рддрд░реНрдХ рдХреЗ рд╕рд╛рде рдмрдбрд╝реА рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ рдкрд░ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЗрд╕рдХреА рд╕рд░рд╛рд╣рдирд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдпрд╣ рдбреАрдбреАрдбреА рдХреА рдкрд░реЗрд╢рд╛рдиреА рд╣реИ, рдХрд┐ рдЗрд╕реЗ рд╣рдореЗрд╢рд╛ рдЫреЛрдЯреЗ рдЙрджрд╛рд╣рд░рдгреЛрдВ рдХреЗ рд╕рд╛рде рд╕рдордЭрд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдЗрд╕ рд╡рд┐рдЪрд╛рд░ рд╕реЗ рдЫреБрдЯрдХрд╛рд░рд╛ рдкрд╛рдирд╛ рдореБрд╢реНрдХрд┐рд▓ рд╣реИ рдХрд┐ рдпрд╣ рд╕рдм рдЦрддреНрдо рд╣реЛ рдЪреБрдХрд╛ рд╣реИред
рд╕рдВрджрд░реНрдн
рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдЙрджрд╛рд╣рд░рдг рдЬрд╣рд╛рдВ рд╕реЗ рд╡рд┐рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХреЛ рд▓рд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рд╡рд╣
рдпрд╣рд╛рдВ рд╣реИ ред рдореИрдВ рдбреАрдбреАрдбреА рдкрд░ рд╕рд╛рд╣рд┐рддреНрдп рдХреА рд╕реВрдЪреА рдХреЗ рд╕рд╛рде рд╣рдм рдкрд░
рдЗрд╕ рд▓реЗрдЦ рдкрд░ рднреА рдзреНрдпрд╛рди рдЖрдХрд░реНрд╖рд┐рдд рдХрд░рддрд╛ рд╣реВрдВред