Adding additional methods to the MemberRepository to support various types of lookups/queries, and experimenting with adding dummy properties to the model so a strongly typed query can be translated using mappers.

GetByQuery needs to be refactored so the selection is done in a subquery, so we don't loose properties in the result set
This commit is contained in:
Morten Christensen
2013-08-28 17:27:29 +02:00
parent 575abc6abf
commit c7351dfad7
6 changed files with 178 additions and 26 deletions

View File

@@ -34,6 +34,9 @@ namespace Umbraco.Core.Models.Membership
private static readonly PropertyInfo DefaultContentTypeIdSelector = ExpressionHelper.GetPropertyInfo<Member, int>(x => x.ContentTypeId);
private static readonly PropertyInfo DefaultContentTypeAliasSelector = ExpressionHelper.GetPropertyInfo<Member, string>(x => x.ContentTypeAlias);
public Member()
{}
/// <summary>
/// Integer Id
/// </summary>
@@ -424,6 +427,16 @@ namespace Umbraco.Core.Models.Membership
public object ProfileId { get; set; }
public IEnumerable<object> Groups { get; set; }
/* Internal experiment - only used for mapping queries.
* Adding these to have first level properties instead of the Properties collection.
*/
internal string LongStringPropertyValue { get; set; }
internal string ShortStringPropertyValue { get; set; }
internal int IntegerropertyValue { get; set; }
internal bool BoolPropertyValue { get; set; }
internal DateTime DateTimePropertyValue { get; set; }
internal string PropertyTypeAlias { get; set; }
#region Internal methods

View File

@@ -6,7 +6,7 @@ using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models.Membership
{
internal abstract class MemberProfile : Profile, IUmbracoEntity
internal class MemberProfile : Profile, IUmbracoEntity
{
private Lazy<int> _parentId;
private int _sortOrder;
@@ -16,12 +16,12 @@ namespace Umbraco.Core.Models.Membership
private bool _trashed;
private PropertyCollection _properties;
private static readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo<MemberProfile, int>(x => ((IUmbracoEntity)x).ParentId);
private static readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo<MemberProfile, int>(x => ((IUmbracoEntity)x).SortOrder);
private static readonly PropertyInfo LevelSelector = ExpressionHelper.GetPropertyInfo<MemberProfile, int>(x => ((IUmbracoEntity)x).Level);
private static readonly PropertyInfo PathSelector = ExpressionHelper.GetPropertyInfo<MemberProfile, string>(x => ((IUmbracoEntity)x).Path);
private static readonly PropertyInfo CreatorIdSelector = ExpressionHelper.GetPropertyInfo<MemberProfile, int>(x => ((IUmbracoEntity)x).CreatorId);
private static readonly PropertyInfo TrashedSelector = ExpressionHelper.GetPropertyInfo<MemberProfile, bool>(x => x.Trashed);
private static readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo<IUmbracoEntity, int>(x => x.ParentId);
private static readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo<IUmbracoEntity, int>(x => x.SortOrder);
private static readonly PropertyInfo LevelSelector = ExpressionHelper.GetPropertyInfo<IUmbracoEntity, int>(x => x.Level);
private static readonly PropertyInfo PathSelector = ExpressionHelper.GetPropertyInfo<IUmbracoEntity, string>(x => x.Path);
private static readonly PropertyInfo CreatorIdSelector = ExpressionHelper.GetPropertyInfo<IUmbracoEntity, int>(x => x.CreatorId);
private static readonly PropertyInfo TrashedSelector = ExpressionHelper.GetPropertyInfo<Member, bool>(x => x.Trashed);
private readonly static PropertyInfo PropertyCollectionSelector = ExpressionHelper.GetPropertyInfo<Member, PropertyCollection>(x => x.Properties);
protected void PropertiesChanged(object sender, NotifyCollectionChangedEventArgs e)
@@ -29,11 +29,14 @@ namespace Umbraco.Core.Models.Membership
OnPropertyChanged(PropertyCollectionSelector);
}
public abstract new int Id { get; set; }
public abstract Guid Key { get; set; }
public abstract DateTime CreateDate { get; set; }
public abstract DateTime UpdateDate { get; set; }
public abstract bool HasIdentity { get; protected set; }
protected MemberProfile()
{}
public virtual new int Id { get; set; }
public virtual Guid Key { get; set; }
public virtual DateTime CreateDate { get; set; }
public virtual DateTime UpdateDate { get; set; }
public virtual bool HasIdentity { get; protected set; }
/// <summary>
/// Profile of the user who created this Content

View File

@@ -12,7 +12,7 @@ namespace Umbraco.Core.Persistence.Factories
{
public IMember BuildEntity(MemberReadOnlyDto dto)
{
var member = new Member
var member = new Member()
{
Id = dto.NodeId,
CreateDate = dto.CreateDate,

View File

@@ -60,6 +60,14 @@ namespace Umbraco.Core.Persistence.Mappers
CacheMap<Member, PropertyDataDto>(src => src.LastLockoutDate, dto => dto.Date);
CacheMap<Member, PropertyDataDto>(src => src.LastLoginDate, dto => dto.Date);
CacheMap<Member, PropertyDataDto>(src => src.LastPasswordChangeDate, dto => dto.Date);
/* Internal experiment */
CacheMap<Member, PropertyDataDto>(src => src.DateTimePropertyValue, dto => dto.Date);
CacheMap<Member, PropertyDataDto>(src => src.IntegerropertyValue, dto => dto.Integer);
CacheMap<Member, PropertyDataDto>(src => src.BoolPropertyValue, dto => dto.Integer);
CacheMap<Member, PropertyDataDto>(src => src.LongStringPropertyValue, dto => dto.Text);
CacheMap<Member, PropertyDataDto>(src => src.ShortStringPropertyValue, dto => dto.VarChar);
CacheMap<Member, PropertyTypeDto>(src => src.PropertyTypeAlias, dto => dto.Alias);
}
#endregion

View File

@@ -250,7 +250,7 @@ namespace Umbraco.Core.Persistence.Querying
case "EndsWith":
return string.Format("upper({0}) like '%{1}'", r, RemoveQuote(args[0].ToString()).ToUpper());
case "Contains":
return string.Format("upper({0}) like '%{1}%'", r, RemoveQuote(args[0].ToString()).ToUpper());
return string.Format("{0} like '%{1}%'", r, RemoveQuote(args[0].ToString()).ToUpper());
case "Substring":
var startIndex = Int32.Parse(args[0].ToString()) + 1;
if (args.Count == 2)

View File

@@ -25,10 +25,10 @@ namespace Umbraco.Core.Persistence.Repositories
* GetById - get a member by its integer Id
* GetByKey - get a member by its unique guid Id (which should correspond to a membership provider user's id)
* GetByUsername - get a member by its username
*
* GetByPropertyValue - get members with a certain property value (supply both property alias and value?)
* GetByMemberTypeAlias - get all members of a certain type
* GetByMemberGroup - get all members in a specific group
* GetAllMembers
*/
#region Overrides of RepositoryBase<int, IMembershipUser>
@@ -43,23 +43,39 @@ namespace Umbraco.Core.Persistence.Repositories
Database.Fetch<MemberReadOnlyDto, PropertyDataReadOnlyDto, MemberReadOnlyDto>(
new PropertyDataRelator().Map, sql);
if (dto == null || dto.Any() == false)
return null;
var factory = new MemberReadOnlyFactory();
var member = factory.BuildEntity(dto.First());
return member;
return BuildFromDto(dto);
}
protected override IEnumerable<IMember> PerformGetAll(params int[] ids)
{
throw new NotImplementedException();
var sql = GetBaseQuery(false);
if (ids.Any())
{
var statement = string.Join(" OR ", ids.Select(x => string.Format("umbracoNode.id='{0}'", x)));
sql.Where(statement);
}
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate);
var dtos =
Database.Fetch<MemberReadOnlyDto, PropertyDataReadOnlyDto, MemberReadOnlyDto>(
new PropertyDataRelator().Map, sql);
return BuildFromDtos(dtos);
}
protected override IEnumerable<IMember> PerformGetByQuery(IQuery<IMember> query)
{
throw new NotImplementedException();
var sqlClause = GetBaseQuery(false);
var translator = new SqlTranslator<IMember>(sqlClause, query);
var sql = translator.Translate()
.OrderByDescending<ContentVersionDto>(x => x.VersionDate)
.OrderBy<NodeDto>(x => x.SortOrder);
var dtos =
Database.Fetch<MemberReadOnlyDto, PropertyDataReadOnlyDto, MemberReadOnlyDto>(
new PropertyDataRelator().Map, sql);
return BuildFromDtos(dtos);
}
#endregion
@@ -68,7 +84,19 @@ namespace Umbraco.Core.Persistence.Repositories
protected override Sql GetBaseQuery(bool isCount)
{
//TODO Count
if (isCount)
{
var sqlCount = new Sql()
.Select("COUNT(*)")
.From<NodeDto>()
.InnerJoin<ContentDto>().On<ContentDto, NodeDto>(left => left.NodeId, right => right.NodeId)
.InnerJoin<ContentTypeDto>().On<ContentTypeDto, ContentDto>(left => left.NodeId, right => right.ContentTypeId)
.InnerJoin<ContentVersionDto>().On<ContentVersionDto, NodeDto>(left => left.NodeId, right => right.NodeId)
.InnerJoin<MemberDto>().On<MemberDto, ContentDto>(left => left.NodeId, right => right.NodeId)
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId);
return sqlCount;
}
var sql = new Sql();
sql.Select("umbracoNode.*", "cmsContent.contentType", "cmsContentType.alias AS ContentTypeAlias", "cmsContentVersion.VersionId",
"cmsContentVersion.VersionDate", "cmsContentVersion.LanguageLocale", "cmsMember.Email",
@@ -98,7 +126,21 @@ namespace Umbraco.Core.Persistence.Repositories
protected override IEnumerable<string> GetDeleteClauses()
{
throw new NotImplementedException();
var list = new List<string>
{
"DELETE FROM umbracoUser2NodeNotify WHERE nodeId = @Id",
"DELETE FROM umbracoUser2NodePermission WHERE nodeId = @Id",
"DELETE FROM umbracoRelation WHERE parentId = @Id",
"DELETE FROM umbracoRelation WHERE childId = @Id",
"DELETE FROM cmsTagRelationship WHERE nodeId = @Id",
"DELETE FROM cmsPropertyData WHERE contentNodeId = @Id",
"DELETE FROM cmsMember WHERE nodeId = @Id",
"DELETE FROM cmsContentVersion WHERE ContentId = @Id",
"DELETE FROM cmsContentXml WHERE nodeID = @Id",
"DELETE FROM cmsContent WHERE NodeId = @Id",
"DELETE FROM umbracoNode WHERE id = @Id"
};
return list;
}
protected override Guid NodeObjectTypeId
@@ -135,5 +177,91 @@ namespace Umbraco.Core.Persistence.Repositories
}
#endregion
//NOTE Might be sufficient to use the GetByQuery method for this, as the mapping should cover it
public IMember GetByKey(Guid key)
{
var sql = GetBaseQuery(false);
sql.Where<NodeDto>(x => x.UniqueId == key);
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate);
var dto =
Database.Fetch<MemberReadOnlyDto, PropertyDataReadOnlyDto, MemberReadOnlyDto>(
new PropertyDataRelator().Map, sql);
return BuildFromDto(dto);
}
//NOTE Might be sufficient to use the GetByQuery method for this, as the mapping should cover it
public IMember GetByUsername(string username)
{
var sql = GetBaseQuery(false);
sql.Where<MemberDto>(x => x.LoginName == username);
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate);
var dto =
Database.Fetch<MemberReadOnlyDto, PropertyDataReadOnlyDto, MemberReadOnlyDto>(
new PropertyDataRelator().Map, sql);
return BuildFromDto(dto);
}
//NOTE Might be sufficient to use the GetByQuery method for this, as the mapping should cover it
public IEnumerable<IMember> GetByMemberTypeAlias(string memberTypeAlias)
{
var sql = GetBaseQuery(false);
sql.Where<ContentTypeDto>(x => x.Alias == memberTypeAlias);
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate);
var dtos =
Database.Fetch<MemberReadOnlyDto, PropertyDataReadOnlyDto, MemberReadOnlyDto>(
new PropertyDataRelator().Map, sql);
return BuildFromDtos(dtos);
}
/*public IEnumerable<IMember> GetByPropertyValue(string value)
{}
public IEnumerable<IMember> GetByPropertyValue(bool value)
{ }
public IEnumerable<IMember> GetByPropertyValue(int value)
{ }
public IEnumerable<IMember> GetByPropertyValue(DateTime value)
{ }
public IEnumerable<IMember> GetByPropertyValue(string propertyTypeAlias, string value)
{ }
public IEnumerable<IMember> GetByPropertyValue(string propertyTypeAlias, bool value)
{ }
public IEnumerable<IMember> GetByPropertyValue(string propertyTypeAlias, int value)
{ }
public IEnumerable<IMember> GetByPropertyValue(string propertyTypeAlias, DateTime value)
{ }*/
private IMember BuildFromDto(List<MemberReadOnlyDto> dtos)
{
if (dtos == null || dtos.Any() == false)
return null;
var factory = new MemberReadOnlyFactory();
var member = factory.BuildEntity(dtos.First());
return member;
}
private IEnumerable<IMember> BuildFromDtos(List<MemberReadOnlyDto> dtos)
{
if (dtos == null || dtos.Any() == false)
return Enumerable.Empty<IMember>();
var factory = new MemberReadOnlyFactory();
return dtos.Select(factory.BuildEntity);
}
}
}