gpt4 book ai didi

c# - 哪个更好?在存储库或域级服务(通过 IQueryable 或其他)中有复杂的搜索逻辑吗?

转载 作者:可可西里 更新时间:2023-11-01 09:09:35 25 4
gpt4 key购买 nike

我需要能够通过多个搜索字段搜索客户帐户。现在,我的存储库中有我的搜索逻辑。搜索逻辑包括一些感觉更像是属于域层的过滤,但这意味着使用 IQueryable 之类的东西,我也不确定我是否喜欢它。

例如,现在我有一个搜索类,其中包含用户可以搜索的所有字段:

public class AccountSearch
{
public decimal Amount { get; set; }
public string CustomerId { get; set; }
public string Address { get; set; }
public string CustomerName { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public string State { get; set; }
}

然后,我有一个域级服务,它只是将搜索类传递给存储库。我不喜欢它:

public class AccountsService : IAccountsService
{
private readonly IAccountRepository _accountRepository;

public AccountsService(IAccountRepository accountRepository)
{
_accountRepository = accountRepository;
}

public IEnumerable<Account> Search(AccountSearch accountSearch)
{
return _accountRepository.Search(accountSearch);
}
}

然后,我在存储库实现中拥有所有过滤逻辑:

public class AccountRepository : IAccountRepository 
{
private AccountDataContext _dataContext;

public AccountRepository(AccountDataContext entityFrameworkDataContext)
{
_dataContext = entityFrameworkDataContext;
}

public IEnumerable<Account> Search(AccountSearch accountSearch)
{
// My datacontext contains database entities, not domain entities.
// This method must query the data context, then map the database
// entities to domain entities.

return _dataContext.Accounts
.Where(TheyMeetSearchCriteria)
.Select(MappedAccounts);
}

// implement expressions here:
// 1. TheyMeetSearchCriteria filters the accounts by the given criteria
// 2. MappedAccounts maps from database to domain entities
}

不确定我是否应该对此感到满意,或者我是否应该找到另一种方法来实现这样的搜索。在这种情况下你会怎么做?

最佳答案

您可以使用多种技术,其中最佳技术取决于您的特定场景。

与其仅仅根据位置(例如在服务中或域中)讨论搜索逻辑,区分规范位置和执行位置可能更有帮助。通过指定位置,我的意思是您在哪些层中指定要搜索的字段。执行位置是指立即执行或延迟执行。

如果您有几种相互排斥的搜索类型(即在场景 A 中您希望通过 CustomerId 进行搜索,而在场景 B 中您希望通过 CustomerName 进行搜索),这可以通过使用专用方法创建特定于域的存储库来实现对于每种搜索类型,或者在 .Net 中,您可以使用 LINQ 表达式。例如:

特定领域的搜索方法:

_customers.WithName("Willie Nelson")

在实现 IQueryable 的存储库上进行 LINQ 查询:

_customers.Where(c => c.Name.Equals("Willie Nelson")

前者允许更具表现力的域,而后者提供更多的使用灵 active ,同时稍微减少开发时间(可能以牺牲可读性为代价)。

对于更复杂的搜索条件需求,您可以使用您描述的传递搜索条件集合(强类型或其他方式)的技术,或者您可以使用 Specification Pattern .规范模式的优点是它提供了一种更具表现力的、领域丰富的查询语言。一个示例用法可能是:

_customers.MeetingCriteria(
Criteria.LivingOutsideUnitedStates.And(Criteria.OlderThan(55)))

通过规范模式提供的组合也可以通过 .Net 的 LINQ API 提供,尽管对指定意图揭示代码的控制较少。

关于执行时间,可以编写存储库以通过返回 IQueryable 或允许传入 LINQ 表达式以由存储库方法计算来提供延迟执行。例如:

延迟查询:

var customer =  (from c in _customers.Query()
where c.Name == "Willie Nelson"
select c).FirstOrDefault();

通过 Query() 方法执行:

var customer =
_customers.Query(q => from c in q
where c.Name == "Willie Nelson"
select c).FirstOrDefault();

返回 IQueryable 的前一个 Query() 方法的优点是稍微容易测试,因为 Query() 可以很容易地 stub 以提供通过调用代码操作的集合,而后者的优点是更确定性的。

=====编辑====

受 gaearon 方法的启发,我决定用类似的技术修改我的答案。他的方法有点像倒置的规范模式,规范执行实际查询。这本质上使它成为一个独立的查询,所以我们就这样调用它:

public class SomeClass
{
// Get the ICustomerQuery through DI
public SomeClass(ICustomerQuery customerQuery)
{
_customerQuery = customerQuery;
}

public void SomeServiceMethod()
{
_customerQuery()
.WhereLivingOutSideUnitedStates()
.WhereAgeGreaterThan(55)
.Select();
}
}

那么,您可能会问存储库在哪里?我们这里不需要。我们的 ICustomerQuery 可以注入(inject)一个 IQueryable ,它可以按照你喜欢的方式实现(也许是一个 IoC 注册,它只为 NHibernate 返回以下内容:

 _container.Resolve<ISession>().Linq<Customer>()

关于c# - 哪个更好?在存储库或域级服务(通过 IQueryable 或其他)中有复杂的搜索逻辑吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4907718/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com