我是 Marten 的新手,对于应该简单的查询感到非常困难。我有一个具有 EmailAddress 类型属性的 Person 类。我想找到任何具有特定电子邮件地址的人。
public class EmailAddress : ValueObject
{
// construction
protected EmailAddress() { } // needed for deserialization
public EmailAddress(EmailType type, string emailAddress)
{
Guard.Against.Null(type, nameof(type));
Guard.Against.NullOrWhiteSpace(emailAddress, nameof(emailAddress));
Guard.Against.NotValidEmail(emailAddress, nameof(emailAddress));
if (!(type.HasFlag(EmailType.Personal) || type.HasFlag(EmailType.Work) || type.HasFlag(EmailType.Other))) throw new ArgumentException("Unable to craete an EmailAddress without a valid type (i.e., Personal, Work, Other).");
Type = type;
Address = emailAddress;
}
// properties
public EmailType Type { get; private set; }
public string Address { get; private set; }
}
public class Person : ValueObject
{
// fields
List<EmailAddress> _emails = new List<EmailAddress>();
// Construction
protected Person() { } // needed for deserialization
public Person(Guid id, string firstName, string lastName, EmailAddress identityAddress)
{
Guard.Against.Default(id, nameof(id));
Guard.Against.NullOrWhiteSpace(firstName, nameof(firstName));
Guard.Against.NullOrWhiteSpace(lastName, nameof(lastName));
Guard.Against.Null(identityAddress, nameof(identityAddress));
if (!identityAddress.Type.HasFlag(EmailType.IsIdentity))
{
identityAddress = new EmailAddress(identityAddress.Type | EmailType.IsIdentity, identityAddress.Address);
}
this.Id = id;
this.FirstName = firstName;
this.LastName = lastName;
_emails.Add(identityAddress);
}
// properties
public Guid Id { get; private set; }
public string FirstName { get; private set; }
public string LastName { get; private set; }
public IReadOnlyList<EmailAddress> Emails { get => _emails; }
}
我创建了一个连接到 PostgreSQl 的测试类,并且能够使用 Marten 插入类型。序列化程序运行良好,能够使用它们的非公共设置器对这些类型进行序列化和反序列化。但是任何与 Person 类型的 Emails 属性相关的查询都会失败。
[TestMethod]
public void Can_Find_Person_Manual()
{
// set the test values
Guid lukeId = Guid.NewGuid();
EmailAddress lukeEmail = new EmailAddress(EmailType.Work | EmailType.IsIdentity, "luke@skywalkerranch.com");
Person lukeSkywalker = new Person(lukeId, "Luke", "Skywalker", lukeEmail);
Guid leiaId = Guid.NewGuid();
EmailAddress leiaEmail = new EmailAddress(EmailType.Personal | EmailType.IsIdentity, "leia@skywalkerranch.com");
Person leiaSolo = new Person(leiaId, "Leia", "Solo", leiaEmail);
// add a test object
IDocumentStore database = _container.GetInstance<IDocumentStore>();
using (var session = database.LightweightSession())
{
// clear prior people
session.DeleteWhere<Person>(p => true);
session.SaveChanges();
// Add new people
session.Store<Person>(lukeSkywalker);
session.Store<Person>(leiaSolo);
session.SaveChanges();
// Start Testing
IReadOnlyList<Person> people = session.LoadMany<Person>(new Guid[] { lukeId, leiaId });
Assert.IsTrue(people.Count == 2);
Person luke = session.Load<Person>(lukeId);
Assert.IsTrue(luke.Id == lukeId);
Assert.IsTrue(luke.Emails.Contains(e => e.Address == "luke@skywalkerranch.com"));
Person foundLuke = session.Query<Person>().Where(p => p.FirstName == "Luke").First();
Assert.IsTrue(foundLuke.Id == lukeId);
Person leia = session.Load<Person>(leiaId);
Assert.IsTrue(leia.Id == leiaId);
Assert.IsTrue(leia.Emails.Contains(e => e.Address == "leia@skywalkerranch.com"));
List<Person> allPeople = session.Query<Person>().ToList(); // works fine 2 items
List<Person> allLeias = session.Query<Person>().Where(p => p.FirstName == "Leia").ToList(); // works fine 1 item
List<Person> allBills = session.Query<Person>().Where(p => p.FirstName == "Bill").ToList(); // works fine 0 items
// List<Person> withEmail = session.Query<Person>().Where(p => p.Emails.Count > 0).ToList(); // ERROR returns empty list
// List<Person> withEmail = session.Query<Person>().Where(p => p.Emails.Count(e => true) > 0).ToList(); // ERROR: select d.data, d.id, d.mt_version from public.mt_doc_person as d where jsonb_array_length(CAST(d.data ->> 'Emails' as jsonb)) > :arg0$ $ 22023: cannot get array length of a non - array'
List<Person> allLukes = session.Query<Person>().Where(p => p.Emails.Any(e => e.Address == "luke@skywalkerranch.com")).ToList(); // ERROR NullreferenceException
//// should get Leia
List<Person> withPersonalEmail = session.Query<Person>().Where(p => p.Emails.Any(e => e.Type == EmailType.Personal)).ToList(); // ERROR returns empty List
List<Person> ranchEmail = session.Query<Person>().Where(p => p.Emails.Any(e => e.Address.Contains("ranch"))).ToList(); // ERROR 'Specific method not supported'
// Below is the one is need
Person foundLeia = session.Query<Person>().Where(p => p.Emails.Any(_ => _.Address == "leia@skywalkerranch.com")).SingleOrDefault(); // ERROR returns null
Assert.IsTrue(foundLeia.Id == leiaId);
}
}