Skip to content

Instantly share code, notes, and snippets.

@felipeleusin
Created March 29, 2011 16:13
Show Gist options
  • Save felipeleusin/892649 to your computer and use it in GitHub Desktop.
Save felipeleusin/892649 to your computer and use it in GitHub Desktop.
Implements IEntityDuplicateChecker to use with RavenDB
public class EntitySignatureIndexGenerator
{
private readonly IDocumentStore documentStore;
public EntitySignatureIndexGenerator(IDocumentStore documentStore)
{
this.documentStore = documentStore;
}
public bool CreateIndexForAssembly(Assembly targetAssembly)
{
var entityTypes = from type in targetAssembly.GetTypes() where type.BaseType == typeof(RavenEntity) select type;
foreach (var entityType in entityTypes)
{
var tag = this.documentStore.Conventions.GetTypeTagName(entityType);
var indexDefinition = BuildIndexDefinition(entityType, tag);
this.documentStore.DatabaseCommands.PutIndex(tag + "/DomainSignature", indexDefinition);
}
return true;
}
private static IndexDefinition BuildIndexDefinition(Type entityType, string entityTagName)
{
var def = new IndexDefinition();
var mapBuilder = new StringBuilder();
mapBuilder.Append(@"Id = doc[""@metadata""][""@id""],");
def.Indexes.Add("Id", FieldIndexing.NotAnalyzed);
def.Stores.Add("Id", FieldStorage.No);
foreach (var signatureProperty in entityType.GetProperties().Where(p => Attribute.IsDefined(p, typeof(DomainSignatureAttribute), true)))
{
mapBuilder.AppendFormat("doc.{0},", signatureProperty.Name);
def.Indexes.Add(signatureProperty.Name, FieldIndexing.NotAnalyzed);
def.Stores.Add(signatureProperty.Name, FieldStorage.No);
}
mapBuilder.Length--;
def.Map = String.Format("from doc in docs.{0} select new {{ {1} }}", entityTagName, mapBuilder);
return def;
}
}
public class RavenEntityDuplicateIdChecker : IEntityDuplicateChecker
{
private readonly IDocumentSession session;
public RavenEntityDuplicateIdChecker(IDocumentSession session)
{
this.session = session;
}
public bool DoesDuplicateExistWithTypedIdOf<IdT>(IEntityWithTypedId<IdT> entity)
{
var indexName = this.session.Advanced.Conventions.GetTypeTagName(entity.GetType()) + "/DomainSignature";
var queryBuilder = new StringBuilder();
AppendSignaturePropertyQueryTo(queryBuilder, entity);
var query = new IndexQuery { Query = queryBuilder.ToString(), PageSize = 1 };
var queryResult = this.session.Advanced.DatabaseCommands.Query(indexName, query, null);
if (queryResult.Results.Count > 0)
{
var returnedId = queryResult.Results[0].SelectToken("@metadata").Value<string>("@id");
if (!returnedId.Equals(entity.Id.ToString(), StringComparison.InvariantCultureIgnoreCase))
{
return true;
}
}
return false;
}
private static void AppendSignaturePropertyQueryTo<IdT>(StringBuilder query, IEntityWithTypedId<IdT> entity)
{
foreach (var signatureProperty in entity.GetSignatureProperties())
{
var name = signatureProperty.Name;
var propertyType = signatureProperty.PropertyType;
var propertyValue = signatureProperty.GetValue(entity, null);
if (propertyType.IsEnum)
{
query.Append(name + ":" + (int)propertyValue + " ");
}
else if (propertyType.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IEntityWithTypedId<>)))
{
AppendEntityQueryTo<IdT>(query, signatureProperty, propertyValue);
}
else if (propertyType == typeof(DateTime))
{
AppendDateTimePropertyQueryTo(query, signatureProperty, propertyValue);
}
else if (propertyType == typeof(string))
{
AppendStringPropertyQueryTo(query, signatureProperty, propertyValue);
}
else if (propertyType.IsValueType)
{
AppendValuePropertyQueryTo(query, signatureProperty, propertyValue);
}
else
{
throw new ApplicationException("Can't determine how to use " + entity.GetType() + "." +
signatureProperty.Name + " when looking for duplicate entries. To remedy this, " +
"you can create a custom validator or report an issue to the S#arp Architecture " +
"project, detailing the type that you'd like to be accommodated.");
}
}
}
private static void AppendStringPropertyQueryTo(StringBuilder query, PropertyInfo signatureProperty, object propertyValue)
{
query.AppendFormat("{0}:{1} ", signatureProperty.Name, propertyValue != null ? "\"" + propertyValue + "\"" : "[[NULL_VALUE]]");
}
private static void AppendDateTimePropertyQueryTo(StringBuilder query, PropertyInfo signatureProperty, object propertyValue)
{
query.AppendFormat("{0}:{1} ", signatureProperty.Name, (DateTime)propertyValue > default(DateTime) ? ((DateTime)propertyValue).ToString("yyyyMMdd") : "[[NULL_VALUE]]");
}
private static void AppendValuePropertyQueryTo(StringBuilder query, PropertyInfo signatureProperty, object propertyValue)
{
query.AppendFormat("{0}:{1} ", signatureProperty.Name, propertyValue ?? "[[NULL_VALUE]]");
}
private static void AppendEntityQueryTo<IdT>(StringBuilder query, PropertyInfo signatureProperty, object propertyValue)
{
if (propertyValue != null)
{
query.AppendFormat("{0}:{1} ", signatureProperty.Name + ".Id", ((IEntityWithTypedId<IdT>)propertyValue).Id);
}
else
{
query.AppendFormat("{0}:{1} ", signatureProperty.Name, "[[NULL_VALUE]]");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment