mirror of
https://github.com/lidarr/lidarr.git
synced 2025-08-20 13:33:34 -07:00
added marr.datamapper source code for easy debugging.
This commit is contained in:
parent
58a05fcef8
commit
3cdff3bb71
96 changed files with 9198 additions and 363 deletions
122
Marr.Data/Mapping/ColumnAttribute.cs
Normal file
122
Marr.Data/Mapping/ColumnAttribute.cs
Normal file
|
@ -0,0 +1,122 @@
|
|||
/* Copyright (C) 2008 - 2011 Jordan Marr
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Data;
|
||||
using System.Data.OleDb;
|
||||
using System.Data.Common;
|
||||
|
||||
namespace Marr.Data.Mapping
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
|
||||
public class ColumnAttribute : Attribute, IColumnInfo
|
||||
{
|
||||
private string _name;
|
||||
private string _altName;
|
||||
private int _size = 0;
|
||||
private bool _isPrimaryKey;
|
||||
private bool _isAutoIncrement;
|
||||
private bool _returnValue;
|
||||
private ParameterDirection _paramDirection = ParameterDirection.Input;
|
||||
|
||||
public ColumnAttribute()
|
||||
{
|
||||
}
|
||||
|
||||
public ColumnAttribute(string name)
|
||||
{
|
||||
_name = name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the column name.
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
set { _name = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an alternate name that is used to define this column in views.
|
||||
/// If an AltName is present, it is used in the QueryViewToObjectGraph method.
|
||||
/// If an AltName is not present, it will return the Name property value.
|
||||
/// </summary>
|
||||
public string AltName
|
||||
{
|
||||
get { return _altName; }
|
||||
set { _altName = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the column size.
|
||||
/// </summary>
|
||||
public int Size
|
||||
{
|
||||
get { return _size; }
|
||||
set { _size = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value that determines whether the column is the Primary Key.
|
||||
/// </summary>
|
||||
public bool IsPrimaryKey
|
||||
{
|
||||
get { return _isPrimaryKey; }
|
||||
set { _isPrimaryKey = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value that determines whether the column is an auto-incrementing seed column.
|
||||
/// </summary>
|
||||
public bool IsAutoIncrement
|
||||
{
|
||||
get { return _isAutoIncrement; }
|
||||
set { _isAutoIncrement = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value that determines whether the column has a return value.
|
||||
/// </summary>
|
||||
public bool ReturnValue
|
||||
{
|
||||
get { return _returnValue; }
|
||||
set { _returnValue = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the ParameterDirection.
|
||||
/// </summary>
|
||||
public ParameterDirection ParamDirection
|
||||
{
|
||||
get { return _paramDirection; }
|
||||
set { _paramDirection = value; }
|
||||
}
|
||||
|
||||
public string TryGetAltName()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(AltName) && AltName != Name)
|
||||
{
|
||||
return AltName;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
38
Marr.Data/Mapping/ColumnInfo.cs
Normal file
38
Marr.Data/Mapping/ColumnInfo.cs
Normal file
|
@ -0,0 +1,38 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Marr.Data.Mapping
|
||||
{
|
||||
public class ColumnInfo : IColumnInfo
|
||||
{
|
||||
public ColumnInfo()
|
||||
{
|
||||
IsPrimaryKey = false;
|
||||
IsAutoIncrement = false;
|
||||
ReturnValue = false;
|
||||
ParamDirection = System.Data.ParameterDirection.Input;
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
public string AltName { get; set; }
|
||||
public int Size { get; set; }
|
||||
public bool IsPrimaryKey { get; set; }
|
||||
public bool IsAutoIncrement { get; set; }
|
||||
public bool ReturnValue { get; set; }
|
||||
public System.Data.ParameterDirection ParamDirection { get; set; }
|
||||
|
||||
public string TryGetAltName()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(AltName) && AltName != Name)
|
||||
{
|
||||
return AltName;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
69
Marr.Data/Mapping/ColumnMap.cs
Normal file
69
Marr.Data/Mapping/ColumnMap.cs
Normal file
|
@ -0,0 +1,69 @@
|
|||
/* Copyright (C) 2008 - 2011 Jordan Marr
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Data;
|
||||
using System.Reflection;
|
||||
using Marr.Data.Converters;
|
||||
|
||||
namespace Marr.Data.Mapping
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains information about the class fields and their associated stored proc parameters
|
||||
/// </summary>
|
||||
public class ColumnMap
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a column map with an empty ColumnInfo object.
|
||||
/// </summary>
|
||||
/// <param name="member">The .net member that is being mapped.</param>
|
||||
public ColumnMap(MemberInfo member)
|
||||
: this(member, new ColumnInfo())
|
||||
{ }
|
||||
|
||||
public ColumnMap(MemberInfo member, IColumnInfo columnInfo)
|
||||
{
|
||||
FieldName = member.Name;
|
||||
|
||||
// If the column name is not specified, the field name will be used.
|
||||
if (string.IsNullOrEmpty(columnInfo.Name))
|
||||
columnInfo.Name = member.Name;
|
||||
|
||||
FieldType = ReflectionHelper.GetMemberType(member);
|
||||
|
||||
Type paramNetType = FieldType;
|
||||
MapRepository repository = MapRepository.Instance;
|
||||
|
||||
IConverter converter = repository.GetConverter(FieldType);
|
||||
if (converter != null)
|
||||
{
|
||||
// Handle conversions
|
||||
paramNetType = converter.DbType;
|
||||
}
|
||||
|
||||
// Get database specific DbType and store with column map in cache
|
||||
DBType = repository.DbTypeBuilder.GetDbType(paramNetType);
|
||||
|
||||
ColumnInfo = columnInfo;
|
||||
}
|
||||
|
||||
public string FieldName { get; set; }
|
||||
public Type FieldType { get; set; }
|
||||
public Enum DBType { get; set; }
|
||||
public IColumnInfo ColumnInfo { get; set; }
|
||||
}
|
||||
}
|
240
Marr.Data/Mapping/ColumnMapBuilder.cs
Normal file
240
Marr.Data/Mapping/ColumnMapBuilder.cs
Normal file
|
@ -0,0 +1,240 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Linq.Expressions;
|
||||
using System.Data;
|
||||
using Marr.Data.Mapping.Strategies;
|
||||
|
||||
namespace Marr.Data.Mapping
|
||||
{
|
||||
/// <summary>
|
||||
/// This class has fluent methods that are used to easily configure column mappings.
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
public class ColumnMapBuilder<TEntity>
|
||||
{
|
||||
private FluentMappings.MappingsFluentEntity<TEntity> _fluentEntity;
|
||||
private string _currentPropertyName;
|
||||
|
||||
public ColumnMapBuilder(FluentMappings.MappingsFluentEntity<TEntity> fluentEntity, ColumnMapCollection mappedColumns)
|
||||
{
|
||||
_fluentEntity = fluentEntity;
|
||||
MappedColumns = mappedColumns;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of column mappings that are being configured.
|
||||
/// </summary>
|
||||
public ColumnMapCollection MappedColumns { get; private set; }
|
||||
|
||||
#region - Fluent Methods -
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the configurator to configure the given property.
|
||||
/// </summary>
|
||||
/// <param name="property"></param>
|
||||
/// <returns></returns>
|
||||
public ColumnMapBuilder<TEntity> For(Expression<Func<TEntity, object>> property)
|
||||
{
|
||||
For(property.GetMemberName());
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the configurator to configure the given property or field.
|
||||
/// </summary>
|
||||
/// <param name="property"></param>
|
||||
/// <returns></returns>
|
||||
public ColumnMapBuilder<TEntity> For(string propertyName)
|
||||
{
|
||||
_currentPropertyName = propertyName;
|
||||
|
||||
// Try to add the column map if it doesn't exist
|
||||
if (MappedColumns.GetByFieldName(_currentPropertyName) == null)
|
||||
{
|
||||
TryAddColumnMapForField(_currentPropertyName);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ColumnMapBuilder<TEntity> SetPrimaryKey()
|
||||
{
|
||||
AssertCurrentPropertyIsSet();
|
||||
return SetPrimaryKey(_currentPropertyName);
|
||||
}
|
||||
|
||||
public ColumnMapBuilder<TEntity> SetPrimaryKey(string propertyName)
|
||||
{
|
||||
MappedColumns.GetByFieldName(propertyName).ColumnInfo.IsPrimaryKey = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ColumnMapBuilder<TEntity> SetAutoIncrement()
|
||||
{
|
||||
AssertCurrentPropertyIsSet();
|
||||
return SetAutoIncrement(_currentPropertyName);
|
||||
}
|
||||
|
||||
public ColumnMapBuilder<TEntity> SetAutoIncrement(string propertyName)
|
||||
{
|
||||
MappedColumns.GetByFieldName(propertyName).ColumnInfo.IsAutoIncrement = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ColumnMapBuilder<TEntity> SetColumnName(string columnName)
|
||||
{
|
||||
AssertCurrentPropertyIsSet();
|
||||
return SetColumnName(_currentPropertyName, columnName);
|
||||
}
|
||||
|
||||
public ColumnMapBuilder<TEntity> SetColumnName(string propertyName, string columnName)
|
||||
{
|
||||
MappedColumns.GetByFieldName(propertyName).ColumnInfo.Name = columnName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ColumnMapBuilder<TEntity> SetReturnValue()
|
||||
{
|
||||
AssertCurrentPropertyIsSet();
|
||||
return SetReturnValue(_currentPropertyName);
|
||||
}
|
||||
|
||||
public ColumnMapBuilder<TEntity> SetReturnValue(string propertyName)
|
||||
{
|
||||
MappedColumns.GetByFieldName(propertyName).ColumnInfo.ReturnValue = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ColumnMapBuilder<TEntity> SetSize(int size)
|
||||
{
|
||||
AssertCurrentPropertyIsSet();
|
||||
return SetSize(_currentPropertyName, size);
|
||||
}
|
||||
|
||||
public ColumnMapBuilder<TEntity> SetSize(string propertyName, int size)
|
||||
{
|
||||
MappedColumns.GetByFieldName(propertyName).ColumnInfo.Size = size;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ColumnMapBuilder<TEntity> SetAltName(string altName)
|
||||
{
|
||||
AssertCurrentPropertyIsSet();
|
||||
return SetAltName(_currentPropertyName, altName);
|
||||
}
|
||||
|
||||
public ColumnMapBuilder<TEntity> SetAltName(string propertyName, string altName)
|
||||
{
|
||||
MappedColumns.GetByFieldName(propertyName).ColumnInfo.AltName = altName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ColumnMapBuilder<TEntity> SetParamDirection(ParameterDirection direction)
|
||||
{
|
||||
AssertCurrentPropertyIsSet();
|
||||
return SetParamDirection(_currentPropertyName, direction);
|
||||
}
|
||||
|
||||
public ColumnMapBuilder<TEntity> SetParamDirection(string propertyName, ParameterDirection direction)
|
||||
{
|
||||
MappedColumns.GetByFieldName(propertyName).ColumnInfo.ParamDirection = direction;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ColumnMapBuilder<TEntity> Ignore(Expression<Func<TEntity, object>> property)
|
||||
{
|
||||
string propertyName = property.GetMemberName();
|
||||
return Ignore(propertyName);
|
||||
}
|
||||
|
||||
public ColumnMapBuilder<TEntity> Ignore(string propertyName)
|
||||
{
|
||||
var columnMap = MappedColumns.GetByFieldName(propertyName);
|
||||
MappedColumns.Remove(columnMap);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ColumnMapBuilder<TEntity> PrefixAltNames(string prefix)
|
||||
{
|
||||
MappedColumns.PrefixAltNames(prefix);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ColumnMapBuilder<TEntity> SuffixAltNames(string suffix)
|
||||
{
|
||||
MappedColumns.SuffixAltNames(suffix);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FluentMappings.MappingsFluentTables<TEntity> Tables
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_fluentEntity == null)
|
||||
{
|
||||
throw new Exception("This property is not compatible with the obsolete 'MapBuilder' class.");
|
||||
}
|
||||
|
||||
return _fluentEntity.Table;
|
||||
}
|
||||
}
|
||||
|
||||
public FluentMappings.MappingsFluentRelationships<TEntity> Relationships
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_fluentEntity == null)
|
||||
{
|
||||
throw new Exception("This property is not compatible with the obsolete 'MapBuilder' class.");
|
||||
}
|
||||
|
||||
return _fluentEntity.Relationships;
|
||||
}
|
||||
}
|
||||
|
||||
public FluentMappings.MappingsFluentEntity<TNewEntity> Entity<TNewEntity>()
|
||||
{
|
||||
return new FluentMappings.MappingsFluentEntity<TNewEntity>(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to add a ColumnMap for the given field name.
|
||||
/// Throws and exception if field cannot be found.
|
||||
/// </summary>
|
||||
private void TryAddColumnMapForField(string fieldName)
|
||||
{
|
||||
// Set strategy to filter for public or private fields
|
||||
ConventionMapStrategy strategy = new ConventionMapStrategy(false);
|
||||
|
||||
// Find the field that matches the given field name
|
||||
strategy.ColumnPredicate = mi => mi.Name == fieldName;
|
||||
ColumnMap columnMap = strategy.MapColumns(typeof(TEntity)).FirstOrDefault();
|
||||
|
||||
if (columnMap == null)
|
||||
{
|
||||
throw new DataMappingException(string.Format("Could not find the field '{0}' in '{1}'.",
|
||||
fieldName,
|
||||
typeof(TEntity).Name));
|
||||
}
|
||||
else
|
||||
{
|
||||
MappedColumns.Add(columnMap);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws an exception if the "current" property has not been set.
|
||||
/// </summary>
|
||||
private void AssertCurrentPropertyIsSet()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_currentPropertyName))
|
||||
{
|
||||
throw new DataMappingException("A property must first be specified using the 'For' method.");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
176
Marr.Data/Mapping/ColumnMapCollection.cs
Normal file
176
Marr.Data/Mapping/ColumnMapCollection.cs
Normal file
|
@ -0,0 +1,176 @@
|
|||
/* Copyright (C) 2008 - 2011 Jordan Marr
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Data;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace Marr.Data.Mapping
|
||||
{
|
||||
/// <summary>
|
||||
/// This class contains a list of column mappings.
|
||||
/// It also provides various methods to filter the collection.
|
||||
/// </summary>
|
||||
public class ColumnMapCollection : List<ColumnMap>
|
||||
{
|
||||
#region - Filters -
|
||||
|
||||
public ColumnMap GetByColumnName(string columnName)
|
||||
{
|
||||
return this.Find(m => m.ColumnInfo.Name == columnName);
|
||||
}
|
||||
|
||||
public ColumnMap GetByFieldName(string fieldName)
|
||||
{
|
||||
return this.Find(m => m.FieldName == fieldName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Iterates through all fields marked as return values.
|
||||
/// </summary>
|
||||
public IEnumerable<ColumnMap> ReturnValues
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (ColumnMap map in this)
|
||||
if (map.ColumnInfo.ReturnValue)
|
||||
yield return map;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Iterates through all fields that are not return values.
|
||||
/// </summary>
|
||||
public ColumnMapCollection NonReturnValues
|
||||
{
|
||||
get
|
||||
{
|
||||
ColumnMapCollection collection = new ColumnMapCollection();
|
||||
|
||||
foreach (ColumnMap map in this)
|
||||
if (!map.ColumnInfo.ReturnValue)
|
||||
collection.Add(map);
|
||||
|
||||
return collection;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Iterates through all fields marked as Output parameters or InputOutput.
|
||||
/// </summary>
|
||||
public IEnumerable<ColumnMap> OutputFields
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (ColumnMap map in this)
|
||||
if (map.ColumnInfo.ParamDirection == ParameterDirection.InputOutput ||
|
||||
map.ColumnInfo.ParamDirection == ParameterDirection.Output)
|
||||
yield return map;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Iterates through all fields marked as primary keys.
|
||||
/// </summary>
|
||||
public ColumnMapCollection PrimaryKeys
|
||||
{
|
||||
get
|
||||
{
|
||||
ColumnMapCollection keys = new ColumnMapCollection();
|
||||
foreach (ColumnMap map in this)
|
||||
if (map.ColumnInfo.IsPrimaryKey)
|
||||
keys.Add(map);
|
||||
|
||||
return keys;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses and orders the parameters from the query text.
|
||||
/// Filters the list of mapped columns to match the parameters found in the sql query.
|
||||
/// All parameters starting with the '@' or ':' symbol are matched and returned.
|
||||
/// </summary>
|
||||
/// <param name="command">The command and parameters that are being parsed.</param>
|
||||
/// <returns>A list of mapped columns that are present in the sql statement as parameters.</returns>
|
||||
public ColumnMapCollection OrderParameters(DbCommand command)
|
||||
{
|
||||
if (command.CommandType == CommandType.Text && this.Count > 0)
|
||||
{
|
||||
string commandTypeString = command.GetType().ToString();
|
||||
if (commandTypeString.Contains("Oracle") || commandTypeString.Contains("OleDb"))
|
||||
{
|
||||
ColumnMapCollection columns = new ColumnMapCollection();
|
||||
|
||||
// Find all @Parameters contained in the sql statement
|
||||
string paramPrefix = commandTypeString.Contains("Oracle") ? ":" : "@";
|
||||
string regexString = string.Format(@"{0}[\w-]+", paramPrefix);
|
||||
Regex regex = new Regex(regexString);
|
||||
foreach (Match m in regex.Matches(command.CommandText))
|
||||
{
|
||||
ColumnMap matchingColumn = this.Find(c => string.Concat(paramPrefix, c.ColumnInfo.Name.ToLower()) == m.Value.ToLower());
|
||||
if (matchingColumn != null)
|
||||
columns.Add(matchingColumn);
|
||||
}
|
||||
|
||||
return columns;
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region - Actions -
|
||||
|
||||
/// <summary>
|
||||
/// Set's each column's altname as the given prefix + the column name.
|
||||
/// Ex:
|
||||
/// Original column name: "ID"
|
||||
/// Passed in prefix: "PRODUCT_"
|
||||
/// Generated AltName: "PRODUCT_ID"
|
||||
/// </summary>
|
||||
/// <param name="prefix">The given prefix.</param>
|
||||
/// <returns></returns>
|
||||
public ColumnMapCollection PrefixAltNames(string prefix)
|
||||
{
|
||||
this.ForEach(c => c.ColumnInfo.AltName = c.ColumnInfo.Name.Insert(0, prefix));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set's each column's altname as the column name + the given prefix.
|
||||
/// Ex:
|
||||
/// Original column name: "ID"
|
||||
/// Passed in suffix: "_PRODUCT"
|
||||
/// Generated AltName: "ID_PRODUCT"
|
||||
/// </summary>
|
||||
/// <param name="suffix"></param>
|
||||
/// <returns></returns>
|
||||
public ColumnMapCollection SuffixAltNames(string suffix)
|
||||
{
|
||||
this.ForEach(c => c.ColumnInfo.AltName = c.ColumnInfo.Name + suffix);
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
29
Marr.Data/Mapping/EnumConversionType.cs
Normal file
29
Marr.Data/Mapping/EnumConversionType.cs
Normal file
|
@ -0,0 +1,29 @@
|
|||
/* Copyright (C) 2008 - 2011 Jordan Marr
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Marr.Data.Mapping
|
||||
{
|
||||
public enum EnumConversionType
|
||||
{
|
||||
NA,
|
||||
Int,
|
||||
String
|
||||
}
|
||||
}
|
236
Marr.Data/Mapping/FluentMappings.cs
Normal file
236
Marr.Data/Mapping/FluentMappings.cs
Normal file
|
@ -0,0 +1,236 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Reflection;
|
||||
using Marr.Data.Mapping.Strategies;
|
||||
using System.Collections;
|
||||
|
||||
namespace Marr.Data.Mapping
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a fluent interface for mapping domain entities and properties to database tables and columns.
|
||||
/// </summary>
|
||||
public class FluentMappings
|
||||
{
|
||||
private bool _publicOnly;
|
||||
|
||||
public FluentMappings()
|
||||
: this(true)
|
||||
{ }
|
||||
|
||||
public FluentMappings(bool publicOnly)
|
||||
{
|
||||
_publicOnly = publicOnly;
|
||||
|
||||
}
|
||||
|
||||
public MappingsFluentEntity<TEntity> Entity<TEntity>()
|
||||
{
|
||||
return new MappingsFluentEntity<TEntity>(_publicOnly);
|
||||
}
|
||||
|
||||
public class MappingsFluentEntity<TEntity>
|
||||
{
|
||||
public MappingsFluentEntity(bool publicOnly)
|
||||
{
|
||||
Columns = new MappingsFluentColumns<TEntity>(this, publicOnly);
|
||||
Table = new MappingsFluentTables<TEntity>(this);
|
||||
Relationships = new MappingsFluentRelationships<TEntity>(this, publicOnly);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Contains methods that map entity properties to database table and view column names;
|
||||
/// </summary>
|
||||
public MappingsFluentColumns<TEntity> Columns { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains methods that map entity classes to database table names.
|
||||
/// </summary>
|
||||
public MappingsFluentTables<TEntity> Table { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains methods that map sub-entities with database table and view column names.
|
||||
/// </summary>
|
||||
public MappingsFluentRelationships<TEntity> Relationships { get; private set; }
|
||||
}
|
||||
|
||||
public class MappingsFluentColumns<TEntity>
|
||||
{
|
||||
private bool _publicOnly;
|
||||
private FluentMappings.MappingsFluentEntity<TEntity> _fluentEntity;
|
||||
|
||||
public MappingsFluentColumns(FluentMappings.MappingsFluentEntity<TEntity> fluentEntity, bool publicOnly)
|
||||
{
|
||||
_fluentEntity = fluentEntity;
|
||||
_publicOnly = publicOnly;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates column mappings for the given type.
|
||||
/// Maps all properties except ICollection properties.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type that is being built.</typeparam>
|
||||
/// <returns><see cref="ColumnMapCollection"/></returns>
|
||||
public ColumnMapBuilder<TEntity> AutoMapAllProperties()
|
||||
{
|
||||
return AutoMapPropertiesWhere(m => m.MemberType == MemberTypes.Property &&
|
||||
!typeof(ICollection).IsAssignableFrom((m as PropertyInfo).PropertyType));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates column mappings for the given type.
|
||||
/// Maps all properties that are simple types (int, string, DateTime, etc).
|
||||
/// ICollection properties are not included.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type that is being built.</typeparam>
|
||||
/// <returns><see cref="ColumnMapCollection"/></returns>
|
||||
public ColumnMapBuilder<TEntity> AutoMapSimpleTypeProperties()
|
||||
{
|
||||
return AutoMapPropertiesWhere(m => m.MemberType == MemberTypes.Property &&
|
||||
DataHelper.IsSimpleType((m as PropertyInfo).PropertyType) &&
|
||||
!typeof(ICollection).IsAssignableFrom((m as PropertyInfo).PropertyType));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates column mappings for the given type if they match the predicate.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type that is being built.</typeparam>
|
||||
/// <param name="predicate">Determines whether a mapping should be created based on the member info.</param>
|
||||
/// <returns><see cref="ColumnMapConfigurator"/></returns>
|
||||
public ColumnMapBuilder<TEntity> AutoMapPropertiesWhere(Func<MemberInfo, bool> predicate)
|
||||
{
|
||||
Type entityType = typeof(TEntity);
|
||||
ConventionMapStrategy strategy = new ConventionMapStrategy(_publicOnly);
|
||||
strategy.ColumnPredicate = predicate;
|
||||
ColumnMapCollection columns = strategy.MapColumns(entityType);
|
||||
MapRepository.Instance.Columns[entityType] = columns;
|
||||
return new ColumnMapBuilder<TEntity>(_fluentEntity, columns);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a ColumnMapBuilder that starts out with no pre-populated columns.
|
||||
/// All columns must be added manually using the builder.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public ColumnMapBuilder<TEntity> MapProperties()
|
||||
{
|
||||
Type entityType = typeof(TEntity);
|
||||
ColumnMapCollection columns = new ColumnMapCollection();
|
||||
MapRepository.Instance.Columns[entityType] = columns;
|
||||
return new ColumnMapBuilder<TEntity>(_fluentEntity, columns);
|
||||
}
|
||||
}
|
||||
|
||||
public class MappingsFluentTables<TEntity>
|
||||
{
|
||||
private FluentMappings.MappingsFluentEntity<TEntity> _fluentEntity;
|
||||
|
||||
public MappingsFluentTables(FluentMappings.MappingsFluentEntity<TEntity> fluentEntity)
|
||||
{
|
||||
_fluentEntity = fluentEntity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides a fluent table mapping interface.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public TableBuilder<TEntity> AutoMapTable<T>()
|
||||
{
|
||||
return new TableBuilder<TEntity>(_fluentEntity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the table name for a given type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="tableName"></param>
|
||||
public TableBuilder<TEntity> MapTable(string tableName)
|
||||
{
|
||||
return new TableBuilder<TEntity>(_fluentEntity).SetTableName(tableName);
|
||||
}
|
||||
}
|
||||
|
||||
public class MappingsFluentRelationships<TEntity>
|
||||
{
|
||||
private FluentMappings.MappingsFluentEntity<TEntity> _fluentEntity;
|
||||
private bool _publicOnly;
|
||||
|
||||
public MappingsFluentRelationships(FluentMappings.MappingsFluentEntity<TEntity> fluentEntity, bool publicOnly)
|
||||
{
|
||||
_fluentEntity = fluentEntity;
|
||||
_publicOnly = publicOnly;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates relationship mappings for the given type.
|
||||
/// Maps all properties that implement ICollection or are not "simple types".
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public RelationshipBuilder<TEntity> AutoMapICollectionOrComplexProperties()
|
||||
{
|
||||
return AutoMapPropertiesWhere(m =>
|
||||
m.MemberType == MemberTypes.Property &&
|
||||
(
|
||||
typeof(ICollection).IsAssignableFrom((m as PropertyInfo).PropertyType) || !DataHelper.IsSimpleType((m as PropertyInfo).PropertyType)
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates relationship mappings for the given type.
|
||||
/// Maps all properties that implement ICollection.
|
||||
/// </summary>
|
||||
/// <returns><see cref="RelationshipBuilder"/></returns>
|
||||
public RelationshipBuilder<TEntity> AutoMapICollectionProperties()
|
||||
{
|
||||
return AutoMapPropertiesWhere(m =>
|
||||
m.MemberType == MemberTypes.Property &&
|
||||
typeof(ICollection).IsAssignableFrom((m as PropertyInfo).PropertyType));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates relationship mappings for the given type.
|
||||
/// Maps all properties that are not "simple types".
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public RelationshipBuilder<TEntity> AutoMapComplexTypeProperties<T>()
|
||||
{
|
||||
return AutoMapPropertiesWhere(m =>
|
||||
m.MemberType == MemberTypes.Property &&
|
||||
!DataHelper.IsSimpleType((m as PropertyInfo).PropertyType));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates relationship mappings for the given type if they match the predicate.
|
||||
/// </summary>
|
||||
/// <param name="predicate">Determines whether a mapping should be created based on the member info.</param>
|
||||
/// <returns><see cref="RelationshipBuilder"/></returns>
|
||||
public RelationshipBuilder<TEntity> AutoMapPropertiesWhere(Func<MemberInfo, bool> predicate)
|
||||
{
|
||||
Type entityType = typeof(TEntity);
|
||||
ConventionMapStrategy strategy = new ConventionMapStrategy(_publicOnly);
|
||||
strategy.RelationshipPredicate = predicate;
|
||||
RelationshipCollection relationships = strategy.MapRelationships(entityType);
|
||||
MapRepository.Instance.Relationships[entityType] = relationships;
|
||||
return new RelationshipBuilder<TEntity>(_fluentEntity, relationships);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a RelationshipBuilder that starts out with no pre-populated relationships.
|
||||
/// All relationships must be added manually using the builder.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public RelationshipBuilder<TEntity> MapProperties<T>()
|
||||
{
|
||||
Type entityType = typeof(T);
|
||||
RelationshipCollection relationships = new RelationshipCollection();
|
||||
MapRepository.Instance.Relationships[entityType] = relationships;
|
||||
return new RelationshipBuilder<TEntity>(_fluentEntity, relationships);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
37
Marr.Data/Mapping/IColumnInfo.cs
Normal file
37
Marr.Data/Mapping/IColumnInfo.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
/* Copyright (C) 2008 - 2011 Jordan Marr
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Data.OleDb;
|
||||
|
||||
namespace Marr.Data.Mapping
|
||||
{
|
||||
public interface IColumnInfo
|
||||
{
|
||||
string Name { get; set; }
|
||||
string AltName { get; set; }
|
||||
int Size { get; set; }
|
||||
bool IsPrimaryKey { get; set; }
|
||||
bool IsAutoIncrement { get; set; }
|
||||
bool ReturnValue { get; set; }
|
||||
ParameterDirection ParamDirection { get; set; }
|
||||
string TryGetAltName();
|
||||
}
|
||||
|
||||
}
|
34
Marr.Data/Mapping/IRelationshipInfo.cs
Normal file
34
Marr.Data/Mapping/IRelationshipInfo.cs
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* Copyright (C) 2008 - 2011 Jordan Marr
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Marr.Data.Mapping
|
||||
{
|
||||
public interface IRelationshipInfo
|
||||
{
|
||||
RelationshipTypes RelationType { get; set; }
|
||||
Type EntityType { get; set; }
|
||||
}
|
||||
|
||||
public enum RelationshipTypes
|
||||
{
|
||||
AutoDetect,
|
||||
One,
|
||||
Many
|
||||
}
|
||||
}
|
208
Marr.Data/Mapping/MapBuilder.cs
Normal file
208
Marr.Data/Mapping/MapBuilder.cs
Normal file
|
@ -0,0 +1,208 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Marr.Data.Mapping.Strategies;
|
||||
using System.Reflection;
|
||||
using System.Collections;
|
||||
|
||||
namespace Marr.Data.Mapping
|
||||
{
|
||||
[Obsolete("This class is obsolete. Please use the 'Mappings' class.")]
|
||||
public class MapBuilder
|
||||
{
|
||||
private bool _publicOnly;
|
||||
|
||||
public MapBuilder()
|
||||
: this(true)
|
||||
{ }
|
||||
|
||||
public MapBuilder(bool publicOnly)
|
||||
{
|
||||
_publicOnly = publicOnly;
|
||||
}
|
||||
|
||||
#region - Columns -
|
||||
|
||||
/// <summary>
|
||||
/// Creates column mappings for the given type.
|
||||
/// Maps all properties except ICollection properties.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type that is being built.</typeparam>
|
||||
/// <returns><see cref="ColumnMapCollection"/></returns>
|
||||
public ColumnMapBuilder<T> BuildColumns<T>()
|
||||
{
|
||||
return BuildColumns<T>(m => m.MemberType == MemberTypes.Property &&
|
||||
!typeof(ICollection).IsAssignableFrom((m as PropertyInfo).PropertyType));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates column mappings for the given type.
|
||||
/// Maps all properties that are simple types (int, string, DateTime, etc).
|
||||
/// ICollection properties are not included.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type that is being built.</typeparam>
|
||||
/// <returns><see cref="ColumnMapCollection"/></returns>
|
||||
public ColumnMapBuilder<T> BuildColumnsFromSimpleTypes<T>()
|
||||
{
|
||||
return BuildColumns<T>(m => m.MemberType == MemberTypes.Property &&
|
||||
DataHelper.IsSimpleType((m as PropertyInfo).PropertyType) &&
|
||||
!typeof(ICollection).IsAssignableFrom((m as PropertyInfo).PropertyType));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates column mappings for the given type.
|
||||
/// Maps properties that are included in the include list.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type that is being built.</typeparam>
|
||||
/// <param name="propertiesToInclude"></param>
|
||||
/// <returns><see cref="ColumnMapCollection"/></returns>
|
||||
public ColumnMapBuilder<T> BuildColumns<T>(params string[] propertiesToInclude)
|
||||
{
|
||||
return BuildColumns<T>(m =>
|
||||
m.MemberType == MemberTypes.Property &&
|
||||
propertiesToInclude.Contains(m.Name));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates column mappings for the given type.
|
||||
/// Maps all properties except the ones in the exclusion list.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type that is being built.</typeparam>
|
||||
/// <param name="propertiesToExclude"></param>
|
||||
/// <returns><see cref="ColumnMapCollection"/></returns>
|
||||
public ColumnMapBuilder<T> BuildColumnsExcept<T>(params string[] propertiesToExclude)
|
||||
{
|
||||
return BuildColumns<T>(m =>
|
||||
m.MemberType == MemberTypes.Property &&
|
||||
!propertiesToExclude.Contains(m.Name));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates column mappings for the given type if they match the predicate.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type that is being built.</typeparam>
|
||||
/// <param name="predicate">Determines whether a mapping should be created based on the member info.</param>
|
||||
/// <returns><see cref="ColumnMapConfigurator"/></returns>
|
||||
public ColumnMapBuilder<T> BuildColumns<T>(Func<MemberInfo, bool> predicate)
|
||||
{
|
||||
Type entityType = typeof(T);
|
||||
ConventionMapStrategy strategy = new ConventionMapStrategy(_publicOnly);
|
||||
strategy.ColumnPredicate = predicate;
|
||||
ColumnMapCollection columns = strategy.MapColumns(entityType);
|
||||
MapRepository.Instance.Columns[entityType] = columns;
|
||||
return new ColumnMapBuilder<T>(null, columns);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a ColumnMapBuilder that starts out with no pre-populated columns.
|
||||
/// All columns must be added manually using the builder.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public ColumnMapBuilder<T> Columns<T>()
|
||||
{
|
||||
Type entityType = typeof(T);
|
||||
ColumnMapCollection columns = new ColumnMapCollection();
|
||||
MapRepository.Instance.Columns[entityType] = columns;
|
||||
return new ColumnMapBuilder<T>(null, columns);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region - Relationships -
|
||||
|
||||
/// <summary>
|
||||
/// Creates relationship mappings for the given type.
|
||||
/// Maps all properties that implement ICollection.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type that is being built.</typeparam>
|
||||
/// <returns><see cref="RelationshipBuilder"/></returns>
|
||||
public RelationshipBuilder<T> BuildRelationships<T>()
|
||||
{
|
||||
return BuildRelationships<T>(m =>
|
||||
m.MemberType == MemberTypes.Property &&
|
||||
typeof(ICollection).IsAssignableFrom((m as PropertyInfo).PropertyType));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates relationship mappings for the given type.
|
||||
/// Maps all properties that are listed in the include list.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type that is being built.</typeparam>
|
||||
/// <param name="propertiesToInclude"></param>
|
||||
/// <returns><see cref="RelationshipBuilder"/></returns>
|
||||
public RelationshipBuilder<T> BuildRelationships<T>(params string[] propertiesToInclude)
|
||||
{
|
||||
Func<MemberInfo, bool> predicate = m =>
|
||||
(
|
||||
// ICollection properties
|
||||
m.MemberType == MemberTypes.Property &&
|
||||
typeof(ICollection).IsAssignableFrom((m as PropertyInfo).PropertyType) &&
|
||||
propertiesToInclude.Contains(m.Name)
|
||||
) || ( // Single entity properties
|
||||
m.MemberType == MemberTypes.Property &&
|
||||
!typeof(ICollection).IsAssignableFrom((m as PropertyInfo).PropertyType) &&
|
||||
propertiesToInclude.Contains(m.Name)
|
||||
);
|
||||
|
||||
return BuildRelationships<T>(predicate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates relationship mappings for the given type if they match the predicate.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type that is being built.</typeparam>
|
||||
/// <param name="predicate">Determines whether a mapping should be created based on the member info.</param>
|
||||
/// <returns><see cref="RelationshipBuilder"/></returns>
|
||||
public RelationshipBuilder<T> BuildRelationships<T>(Func<MemberInfo, bool> predicate)
|
||||
{
|
||||
Type entityType = typeof(T);
|
||||
ConventionMapStrategy strategy = new ConventionMapStrategy(_publicOnly);
|
||||
strategy.RelationshipPredicate = predicate;
|
||||
RelationshipCollection relationships = strategy.MapRelationships(entityType);
|
||||
MapRepository.Instance.Relationships[entityType] = relationships;
|
||||
return new RelationshipBuilder<T>(null, relationships);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a RelationshipBuilder that starts out with no pre-populated relationships.
|
||||
/// All relationships must be added manually using the builder.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public RelationshipBuilder<T> Relationships<T>()
|
||||
{
|
||||
Type entityType = typeof(T);
|
||||
RelationshipCollection relationships = new RelationshipCollection();
|
||||
MapRepository.Instance.Relationships[entityType] = relationships;
|
||||
return new RelationshipBuilder<T>(null, relationships);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region - Tables -
|
||||
|
||||
/// <summary>
|
||||
/// Provides a fluent table mapping interface.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public TableBuilder<T> BuildTable<T>()
|
||||
{
|
||||
return new TableBuilder<T>(null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the table name for a given type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="tableName"></param>
|
||||
public TableBuilder<T> BuildTable<T>(string tableName)
|
||||
{
|
||||
return new TableBuilder<T>(null).SetTableName(tableName);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
185
Marr.Data/Mapping/MappingHelper.cs
Normal file
185
Marr.Data/Mapping/MappingHelper.cs
Normal file
|
@ -0,0 +1,185 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Data.Common;
|
||||
using Marr.Data.Converters;
|
||||
|
||||
namespace Marr.Data.Mapping
|
||||
{
|
||||
internal class MappingHelper
|
||||
{
|
||||
private MapRepository _repos;
|
||||
private IDataMapper _db;
|
||||
|
||||
public MappingHelper(IDataMapper db)
|
||||
{
|
||||
_repos = MapRepository.Instance;
|
||||
_db = db;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates an entity and loads its mapped fields with the data from the reader.
|
||||
/// </summary>
|
||||
public object CreateAndLoadEntity<T>(ColumnMapCollection mappings, DbDataReader reader, bool useAltName)
|
||||
{
|
||||
return CreateAndLoadEntity(typeof(T), mappings, reader, useAltName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates an entity and loads its mapped fields with the data from the reader.
|
||||
/// </summary>
|
||||
/// <param name="entityType">The entity being created and loaded.</param>
|
||||
/// <param name="mappings">The field mappings for the passed in entity.</param>
|
||||
/// <param name="reader">The open data reader.</param>
|
||||
/// <param name="useAltNames">Determines if the column AltName should be used.</param>
|
||||
/// <returns>Returns an entity loaded with data.</returns>
|
||||
public object CreateAndLoadEntity(Type entityType, ColumnMapCollection mappings, DbDataReader reader, bool useAltName)
|
||||
{
|
||||
// Create new entity
|
||||
object ent = _repos.ReflectionStrategy.CreateInstance(entityType);
|
||||
return LoadExistingEntity(mappings, reader, ent, useAltName);
|
||||
}
|
||||
|
||||
public object LoadExistingEntity(ColumnMapCollection mappings, DbDataReader reader, object ent, bool useAltName)
|
||||
{
|
||||
// Populate entity fields from data reader
|
||||
foreach (ColumnMap dataMap in mappings)
|
||||
{
|
||||
try
|
||||
{
|
||||
string colName = dataMap.ColumnInfo.GetColumName(useAltName);
|
||||
int ordinal = reader.GetOrdinal(colName);
|
||||
object dbValue = reader.GetValue(ordinal);
|
||||
|
||||
// Handle conversions
|
||||
IConverter conversion = _repos.GetConverter(dataMap.FieldType);
|
||||
if (conversion != null)
|
||||
{
|
||||
dbValue = conversion.FromDB(dataMap, dbValue);
|
||||
}
|
||||
|
||||
_repos.ReflectionStrategy.SetFieldValue(ent, dataMap.FieldName, dbValue);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = string.Format("The DataMapper was unable to load the following field: '{0}'.",
|
||||
dataMap.ColumnInfo.Name);
|
||||
|
||||
throw new DataMappingException(msg, ex);
|
||||
}
|
||||
}
|
||||
|
||||
PrepareLazyLoadedProperties(ent);
|
||||
|
||||
return ent;
|
||||
}
|
||||
|
||||
private void PrepareLazyLoadedProperties(object ent)
|
||||
{
|
||||
// Handle lazy loaded properties
|
||||
Type entType = ent.GetType();
|
||||
if (_repos.Relationships.ContainsKey(entType))
|
||||
{
|
||||
Func<IDataMapper> dbCreate = () =>
|
||||
{
|
||||
var db = new DataMapper(_db.ProviderFactory, _db.ConnectionString);
|
||||
db.SqlMode = SqlModes.Text;
|
||||
return db;
|
||||
};
|
||||
|
||||
var relationships = _repos.Relationships[entType];
|
||||
foreach (var rel in relationships.Where(r => r.IsLazyLoaded))
|
||||
{
|
||||
ILazyLoaded lazyLoaded = (ILazyLoaded)rel.LazyLoaded.Clone();
|
||||
lazyLoaded.Prepare(dbCreate, ent);
|
||||
_repos.ReflectionStrategy.SetFieldValue(ent, rel.Member.Name, lazyLoaded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public T LoadSimpleValueFromFirstColumn<T>(DbDataReader reader)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (T)reader.GetValue(0);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string firstColumnName = reader.GetName(0);
|
||||
string msg = string.Format("The DataMapper was unable to create a value of type '{0}' from the first column '{1}'.",
|
||||
typeof(T).Name, firstColumnName);
|
||||
|
||||
throw new DataMappingException(msg, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates all parameters for a SP based on the mappings of the entity,
|
||||
/// and assigns them values based on the field values of the entity.
|
||||
/// </summary>
|
||||
public void CreateParameters<T>(T entity, ColumnMapCollection columnMapCollection, bool isAutoQuery)
|
||||
{
|
||||
ColumnMapCollection mappings = columnMapCollection;
|
||||
|
||||
if (!isAutoQuery)
|
||||
{
|
||||
// Order columns (applies to Oracle and OleDb only)
|
||||
mappings = columnMapCollection.OrderParameters(_db.Command);
|
||||
}
|
||||
|
||||
foreach (ColumnMap columnMap in mappings)
|
||||
{
|
||||
if (columnMap.ColumnInfo.IsAutoIncrement)
|
||||
continue;
|
||||
|
||||
var param = _db.Command.CreateParameter();
|
||||
param.ParameterName = columnMap.ColumnInfo.Name;
|
||||
param.Size = columnMap.ColumnInfo.Size;
|
||||
param.Direction = columnMap.ColumnInfo.ParamDirection;
|
||||
|
||||
object val = _repos.ReflectionStrategy.GetFieldValue(entity, columnMap.FieldName);
|
||||
|
||||
param.Value = val == null ? DBNull.Value : val; // Convert nulls to DBNulls
|
||||
|
||||
var repos = MapRepository.Instance;
|
||||
|
||||
IConverter conversion = repos.GetConverter(columnMap.FieldType);
|
||||
if (conversion != null)
|
||||
{
|
||||
param.Value = conversion.ToDB(param.Value);
|
||||
}
|
||||
|
||||
// Set the appropriate DbType property depending on the parameter type
|
||||
// Note: the columnMap.DBType property was set when the ColumnMap was created
|
||||
repos.DbTypeBuilder.SetDbType(param, columnMap.DBType);
|
||||
|
||||
_db.Command.Parameters.Add(param);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Assigns the SP result columns to the passed in 'mappings' fields.
|
||||
/// </summary>
|
||||
public void SetOutputValues<T>(T entity, IEnumerable<ColumnMap> mappings)
|
||||
{
|
||||
foreach (ColumnMap dataMap in mappings)
|
||||
{
|
||||
object output = _db.Command.Parameters[dataMap.ColumnInfo.Name].Value;
|
||||
_repos.ReflectionStrategy.SetFieldValue(entity, dataMap.FieldName, output);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Assigns the passed in 'value' to the passed in 'mappings' fields.
|
||||
/// </summary>
|
||||
public void SetOutputValues<T>(T entity, IEnumerable<ColumnMap> mappings, object value)
|
||||
{
|
||||
foreach (ColumnMap dataMap in mappings)
|
||||
{
|
||||
_repos.ReflectionStrategy.SetFieldValue(entity, dataMap.FieldName, Convert.ChangeType(value, dataMap.FieldType));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
120
Marr.Data/Mapping/Relationship.cs
Normal file
120
Marr.Data/Mapping/Relationship.cs
Normal file
|
@ -0,0 +1,120 @@
|
|||
/* Copyright (C) 2008 - 2011 Jordan Marr
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Marr.Data.Mapping
|
||||
{
|
||||
public class Relationship
|
||||
{
|
||||
private IRelationshipInfo _relationshipInfo;
|
||||
private MemberInfo _member;
|
||||
private ILazyLoaded _lazyLoaded;
|
||||
|
||||
public Relationship(MemberInfo member)
|
||||
: this(member, new RelationshipInfo())
|
||||
{ }
|
||||
|
||||
public Relationship(MemberInfo member, IRelationshipInfo relationshipInfo)
|
||||
{
|
||||
_member = member;
|
||||
|
||||
Type memberType = ReflectionHelper.GetMemberType(member);
|
||||
|
||||
// Try to determine the RelationshipType
|
||||
if (relationshipInfo.RelationType == RelationshipTypes.AutoDetect)
|
||||
{
|
||||
if (typeof(System.Collections.ICollection).IsAssignableFrom(memberType))
|
||||
{
|
||||
relationshipInfo.RelationType = RelationshipTypes.Many;
|
||||
}
|
||||
else
|
||||
{
|
||||
relationshipInfo.RelationType = RelationshipTypes.One;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to determine the EntityType
|
||||
if (relationshipInfo.EntityType == null)
|
||||
{
|
||||
if (relationshipInfo.RelationType == RelationshipTypes.Many)
|
||||
{
|
||||
if (memberType.IsGenericType)
|
||||
{
|
||||
// Assume a Collection<T> or List<T> and return T
|
||||
relationshipInfo.EntityType = memberType.GetGenericArguments()[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException(string.Format(
|
||||
"The DataMapper could not determine the RelationshipAttribute EntityType for {0}.",
|
||||
memberType.Name));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
relationshipInfo.EntityType = memberType;
|
||||
}
|
||||
}
|
||||
|
||||
_relationshipInfo = relationshipInfo;
|
||||
}
|
||||
|
||||
public IRelationshipInfo RelationshipInfo
|
||||
{
|
||||
get { return _relationshipInfo; }
|
||||
}
|
||||
|
||||
public MemberInfo Member
|
||||
{
|
||||
get { return _member; }
|
||||
}
|
||||
|
||||
public Type MemberType
|
||||
{
|
||||
get
|
||||
{
|
||||
// Assumes that a relationship can only have a member type of Field or Property
|
||||
if (Member.MemberType == MemberTypes.Field)
|
||||
return (Member as FieldInfo).FieldType;
|
||||
else
|
||||
return (Member as PropertyInfo).PropertyType;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsLazyLoaded
|
||||
{
|
||||
get
|
||||
{
|
||||
return _lazyLoaded != null;
|
||||
}
|
||||
}
|
||||
|
||||
public ILazyLoaded LazyLoaded
|
||||
{
|
||||
get
|
||||
{
|
||||
return _lazyLoaded;
|
||||
}
|
||||
set
|
||||
{
|
||||
_lazyLoaded = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
77
Marr.Data/Mapping/RelationshipAttribute.cs
Normal file
77
Marr.Data/Mapping/RelationshipAttribute.cs
Normal file
|
@ -0,0 +1,77 @@
|
|||
/* Copyright (C) 2008 - 2011 Jordan Marr
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Marr.Data.Mapping
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a field as a related entity that needs to be created at filled with data.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
|
||||
public class RelationshipAttribute : Attribute, IRelationshipInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a data relationship.
|
||||
/// </summary>
|
||||
public RelationshipAttribute()
|
||||
: this(RelationshipTypes.AutoDetect)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Defines a data relationship.
|
||||
/// </summary>
|
||||
/// <param name="relationType"></param>
|
||||
public RelationshipAttribute(RelationshipTypes relationType)
|
||||
{
|
||||
RelationType = relationType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines a One-ToMany data relationship for a given type.
|
||||
/// </summary>
|
||||
/// <param name="entityType">The type of the child entity.</param>
|
||||
public RelationshipAttribute(Type entityType)
|
||||
: this(entityType, RelationshipTypes.AutoDetect)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Defines a data relationship.
|
||||
/// </summary>
|
||||
/// <param name="entityType">The type of the child entity.</param>
|
||||
/// <param name="relationType">The relationship type can be "One" or "Many".</param>
|
||||
public RelationshipAttribute(Type entityType, RelationshipTypes relationType)
|
||||
{
|
||||
EntityType = entityType;
|
||||
RelationType = relationType;
|
||||
}
|
||||
|
||||
#region IRelationshipInfo Members
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the relationship type can be "One" or "Many".
|
||||
/// </summary>
|
||||
public RelationshipTypes RelationType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type of the child entity.
|
||||
/// </summary>
|
||||
public Type EntityType { get; set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
176
Marr.Data/Mapping/RelationshipBuilder.cs
Normal file
176
Marr.Data/Mapping/RelationshipBuilder.cs
Normal file
|
@ -0,0 +1,176 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Linq.Expressions;
|
||||
using Marr.Data.Mapping.Strategies;
|
||||
|
||||
namespace Marr.Data.Mapping
|
||||
{
|
||||
/// <summary>
|
||||
/// This class has fluent methods that are used to easily configure relationship mappings.
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
public class RelationshipBuilder<TEntity>
|
||||
{
|
||||
private FluentMappings.MappingsFluentEntity<TEntity> _fluentEntity;
|
||||
private string _currentPropertyName;
|
||||
|
||||
public RelationshipBuilder(FluentMappings.MappingsFluentEntity<TEntity> fluentEntity, RelationshipCollection relationships)
|
||||
{
|
||||
_fluentEntity = fluentEntity;
|
||||
Relationships = relationships;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of relationship mappings that are being configured.
|
||||
/// </summary>
|
||||
public RelationshipCollection Relationships { get; private set; }
|
||||
|
||||
#region - Fluent Methods -
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the configurator to configure the given property.
|
||||
/// </summary>
|
||||
/// <param name="property"></param>
|
||||
/// <returns></returns>
|
||||
public RelationshipBuilder<TEntity> For(Expression<Func<TEntity, object>> property)
|
||||
{
|
||||
return For(property.GetMemberName());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the configurator to configure the given property or field.
|
||||
/// </summary>
|
||||
/// <param name="propertyName"></param>
|
||||
/// <returns></returns>
|
||||
public RelationshipBuilder<TEntity> For(string propertyName)
|
||||
{
|
||||
_currentPropertyName = propertyName;
|
||||
|
||||
// Try to add the relationship if it doesn't exist
|
||||
if (Relationships[_currentPropertyName] == null)
|
||||
{
|
||||
TryAddRelationshipForField(_currentPropertyName);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a property to be lazy loaded, with a given query.
|
||||
/// </summary>
|
||||
/// <typeparam name="TChild"></typeparam>
|
||||
/// <param name="query"></param>
|
||||
/// <returns></returns>
|
||||
public RelationshipBuilder<TEntity> LazyLoad<TChild>(Func<IDataMapper, TEntity, TChild> query)
|
||||
{
|
||||
AssertCurrentPropertyIsSet();
|
||||
|
||||
Relationships[_currentPropertyName].LazyLoaded = new LazyLoaded<TEntity, TChild>(query);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RelationshipBuilder<TEntity> SetOneToOne()
|
||||
{
|
||||
AssertCurrentPropertyIsSet();
|
||||
SetOneToOne(_currentPropertyName);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RelationshipBuilder<TEntity> SetOneToOne(string propertyName)
|
||||
{
|
||||
Relationships[propertyName].RelationshipInfo.RelationType = RelationshipTypes.One;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RelationshipBuilder<TEntity> SetOneToMany()
|
||||
{
|
||||
AssertCurrentPropertyIsSet();
|
||||
SetOneToMany(_currentPropertyName);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RelationshipBuilder<TEntity> SetOneToMany(string propertyName)
|
||||
{
|
||||
Relationships[propertyName].RelationshipInfo.RelationType = RelationshipTypes.Many;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RelationshipBuilder<TEntity> Ignore(Expression<Func<TEntity, object>> property)
|
||||
{
|
||||
string propertyName = property.GetMemberName();
|
||||
Relationships.RemoveAll(r => r.Member.Name == propertyName);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FluentMappings.MappingsFluentTables<TEntity> Tables
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_fluentEntity == null)
|
||||
{
|
||||
throw new Exception("This property is not compatible with the obsolete 'MapBuilder' class.");
|
||||
}
|
||||
|
||||
return _fluentEntity.Table;
|
||||
}
|
||||
}
|
||||
|
||||
public FluentMappings.MappingsFluentColumns<TEntity> Columns
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_fluentEntity == null)
|
||||
{
|
||||
throw new Exception("This property is not compatible with the obsolete 'MapBuilder' class.");
|
||||
}
|
||||
|
||||
return _fluentEntity.Columns;
|
||||
}
|
||||
}
|
||||
|
||||
public FluentMappings.MappingsFluentEntity<TNewEntity> Entity<TNewEntity>()
|
||||
{
|
||||
return new FluentMappings.MappingsFluentEntity<TNewEntity>(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to add a Relationship for the given field name.
|
||||
/// Throws and exception if field cannot be found.
|
||||
/// </summary>
|
||||
private void TryAddRelationshipForField(string fieldName)
|
||||
{
|
||||
// Set strategy to filter for public or private fields
|
||||
ConventionMapStrategy strategy = new ConventionMapStrategy(false);
|
||||
|
||||
// Find the field that matches the given field name
|
||||
strategy.RelationshipPredicate = mi => mi.Name == fieldName;
|
||||
Relationship relationship = strategy.MapRelationships(typeof(TEntity)).FirstOrDefault();
|
||||
|
||||
if (relationship == null)
|
||||
{
|
||||
throw new DataMappingException(string.Format("Could not find the field '{0}' in '{1}'.",
|
||||
fieldName,
|
||||
typeof(TEntity).Name));
|
||||
}
|
||||
else
|
||||
{
|
||||
Relationships.Add(relationship);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws an exception if the "current" property has not been set.
|
||||
/// </summary>
|
||||
private void AssertCurrentPropertyIsSet()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_currentPropertyName))
|
||||
{
|
||||
throw new DataMappingException("A property must first be specified using the 'For' method.");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
37
Marr.Data/Mapping/RelationshipCollection.cs
Normal file
37
Marr.Data/Mapping/RelationshipCollection.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
/* Copyright (C) 2008 - 2011 Jordan Marr
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Marr.Data.Mapping
|
||||
{
|
||||
public class RelationshipCollection : List<Relationship>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a ColumnMap by its field name.
|
||||
/// </summary>
|
||||
/// <param name="fieldName"></param>
|
||||
/// <returns></returns>
|
||||
public Relationship this[string fieldName]
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.Find(m => m.Member.Name == fieldName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
14
Marr.Data/Mapping/RelationshipInfo.cs
Normal file
14
Marr.Data/Mapping/RelationshipInfo.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Marr.Data.Mapping
|
||||
{
|
||||
public class RelationshipInfo : IRelationshipInfo
|
||||
{
|
||||
public RelationshipTypes RelationType { get; set; }
|
||||
|
||||
public Type EntityType { get; set; }
|
||||
}
|
||||
}
|
75
Marr.Data/Mapping/Strategies/AttributeMapStrategy.cs
Normal file
75
Marr.Data/Mapping/Strategies/AttributeMapStrategy.cs
Normal file
|
@ -0,0 +1,75 @@
|
|||
/* Copyright (C) 2008 - 2011 Jordan Marr
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Reflection;
|
||||
using Marr.Data.Converters;
|
||||
using Marr.Data.Parameters;
|
||||
|
||||
namespace Marr.Data.Mapping.Strategies
|
||||
{
|
||||
/// <summary>
|
||||
/// Maps fields or properties that are marked with the ColumnAttribute.
|
||||
/// </summary>
|
||||
public class AttributeMapStrategy : ReflectionMapStrategyBase
|
||||
{
|
||||
public AttributeMapStrategy()
|
||||
: base()
|
||||
{ }
|
||||
|
||||
public AttributeMapStrategy(bool publicOnly)
|
||||
: base(publicOnly)
|
||||
{ }
|
||||
|
||||
public AttributeMapStrategy(BindingFlags flags)
|
||||
: base(flags)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Registers any member with a ColumnAttribute as a ColumnMap.
|
||||
/// <param name="entityType">The entity that is being mapped.</param>
|
||||
/// <param name="member">The current member that is being inspected.</param>
|
||||
/// <param name="columnAtt">A ColumnAttribute (is null of one does not exist).</param>
|
||||
/// <param name="columnMaps">A list of ColumnMaps.</param>
|
||||
/// </summary>
|
||||
protected override void CreateColumnMap(Type entityType, MemberInfo member, ColumnAttribute columnAtt, ColumnMapCollection columnMaps)
|
||||
{
|
||||
if (columnAtt != null)
|
||||
{
|
||||
ColumnMap columnMap = new ColumnMap(member, columnAtt);
|
||||
columnMaps.Add(columnMap);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers any member with a RelationshipAttribute as a relationship.
|
||||
/// </summary>
|
||||
/// <param name="entityType">The entity that is being mapped.</param>
|
||||
/// <param name="member">The current member that is being inspected.</param>
|
||||
/// <param name="relationshipAtt">A RelationshipAttribute (is null if one does not exist).</param>
|
||||
/// <param name="relationships">A list of Relationships.</param>
|
||||
protected override void CreateRelationship(Type entityType, MemberInfo member, RelationshipAttribute relationshipAtt, RelationshipCollection relationships)
|
||||
{
|
||||
if (relationshipAtt != null)
|
||||
{
|
||||
Relationship relationship = new Relationship(member, relationshipAtt);
|
||||
relationships.Add(relationship);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
51
Marr.Data/Mapping/Strategies/ConventionMapStrategy.cs
Normal file
51
Marr.Data/Mapping/Strategies/ConventionMapStrategy.cs
Normal file
|
@ -0,0 +1,51 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Reflection;
|
||||
using System.Collections;
|
||||
|
||||
namespace Marr.Data.Mapping.Strategies
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows you to specify a member based filter by defining predicates that filter the members that are mapped.
|
||||
/// </summary>
|
||||
public class ConventionMapStrategy : ReflectionMapStrategyBase
|
||||
{
|
||||
public ConventionMapStrategy(bool publicOnly)
|
||||
: base(publicOnly)
|
||||
{
|
||||
// Default: Only map members that are properties
|
||||
ColumnPredicate = m => m.MemberType == MemberTypes.Property;
|
||||
|
||||
// Default: Only map members that are properties and that are ICollection types
|
||||
RelationshipPredicate = m =>
|
||||
{
|
||||
return m.MemberType == MemberTypes.Property && typeof(ICollection).IsAssignableFrom((m as PropertyInfo).PropertyType);
|
||||
};
|
||||
}
|
||||
|
||||
public Func<MemberInfo, bool> ColumnPredicate;
|
||||
public Func<MemberInfo, bool> RelationshipPredicate;
|
||||
|
||||
|
||||
|
||||
protected override void CreateColumnMap(Type entityType, System.Reflection.MemberInfo member, ColumnAttribute columnAtt, ColumnMapCollection columnMaps)
|
||||
{
|
||||
if (ColumnPredicate(member))
|
||||
{
|
||||
// Map public property to DB column
|
||||
columnMaps.Add(new ColumnMap(member));
|
||||
}
|
||||
}
|
||||
|
||||
protected override void CreateRelationship(Type entityType, System.Reflection.MemberInfo member, RelationshipAttribute relationshipAtt, RelationshipCollection relationships)
|
||||
{
|
||||
if (RelationshipPredicate(member))
|
||||
{
|
||||
relationships.Add(new Relationship(member));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
48
Marr.Data/Mapping/Strategies/IMapStrategy.cs
Normal file
48
Marr.Data/Mapping/Strategies/IMapStrategy.cs
Normal file
|
@ -0,0 +1,48 @@
|
|||
/* Copyright (C) 2008 - 2011 Jordan Marr
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Marr.Data.Mapping.Strategies
|
||||
{
|
||||
/// <summary>
|
||||
/// A strategy for creating mappings for a given entity.
|
||||
/// </summary>
|
||||
public interface IMapStrategy
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a table map for a given entity type.
|
||||
/// </summary>
|
||||
/// <param name="entityType"></param>
|
||||
/// <returns></returns>
|
||||
string MapTable(Type entityType);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a ColumnMapCollection for a given entity type.
|
||||
/// </summary>
|
||||
/// <param name="entityType">The entity that is being mapped.</param>
|
||||
ColumnMapCollection MapColumns(Type entityType);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a RelationshpCollection for a given entity type.
|
||||
/// </summary>
|
||||
/// <param name="entityType">The entity that is being mapped.</param>
|
||||
/// <returns></returns>
|
||||
RelationshipCollection MapRelationships(Type entityType);
|
||||
}
|
||||
}
|
85
Marr.Data/Mapping/Strategies/PropertyMapStrategy.cs
Normal file
85
Marr.Data/Mapping/Strategies/PropertyMapStrategy.cs
Normal file
|
@ -0,0 +1,85 @@
|
|||
/* Copyright (C) 2008 - 2011 Jordan Marr
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Marr.Data.Mapping.Strategies
|
||||
{
|
||||
/// <summary>
|
||||
/// Maps all public properties to DB columns.
|
||||
/// </summary>
|
||||
public class PropertyMapStrategy : AttributeMapStrategy
|
||||
{
|
||||
public PropertyMapStrategy(bool publicOnly)
|
||||
: base(publicOnly)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Maps properties to DB columns if a ColumnAttribute is not present.
|
||||
/// <param name="entityType">The entity that is being mapped.</param>
|
||||
/// <param name="member">The current member that is being inspected.</param>
|
||||
/// <param name="columnAtt">A ColumnAttribute (is null of one does not exist).</param>
|
||||
/// <param name="columnMaps">A list of ColumnMaps.</param>
|
||||
/// </summary>
|
||||
protected override void CreateColumnMap(Type entityType, MemberInfo member, ColumnAttribute columnAtt, ColumnMapCollection columnMaps)
|
||||
{
|
||||
if (columnAtt != null)
|
||||
{
|
||||
// Add columns with ColumnAttribute
|
||||
base.CreateColumnMap(entityType, member, columnAtt, columnMaps);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (member.MemberType == MemberTypes.Property)
|
||||
{
|
||||
// Map public property to DB column
|
||||
columnMaps.Add(new ColumnMap(member));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps a relationship if a RelationshipAttribute is present.
|
||||
/// </summary>
|
||||
/// <param name="entityType">The entity that is being mapped.</param>
|
||||
/// <param name="member">The current member that is being inspected.</param>
|
||||
/// <param name="relationshipAtt">A RelationshipAttribute (is null if one does not exist).</param>
|
||||
/// <param name="relationships">A list of Relationships.</param>
|
||||
protected override void CreateRelationship(Type entityType, MemberInfo member, RelationshipAttribute relationshipAtt, RelationshipCollection relationships)
|
||||
{
|
||||
if (relationshipAtt != null)
|
||||
{
|
||||
// Add relationships by RelationshipAttribute
|
||||
base.CreateRelationship(entityType, member, relationshipAtt, relationships);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (member.MemberType == MemberTypes.Property)
|
||||
{
|
||||
PropertyInfo propertyInfo = member as PropertyInfo;
|
||||
if (typeof(System.Collections.ICollection).IsAssignableFrom(propertyInfo.PropertyType))
|
||||
{
|
||||
Relationship relationship = new Relationship(member);
|
||||
relationships.Add(relationship);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
151
Marr.Data/Mapping/Strategies/ReflectionMapStrategyBase.cs
Normal file
151
Marr.Data/Mapping/Strategies/ReflectionMapStrategyBase.cs
Normal file
|
@ -0,0 +1,151 @@
|
|||
/* Copyright (C) 2008 - 2011 Jordan Marr
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Marr.Data.Mapping.Strategies
|
||||
{
|
||||
/// <summary>
|
||||
/// Iterates through the members of an entity based on the BindingFlags, and provides an abstract method for adding ColumnMaps for each member.
|
||||
/// </summary>
|
||||
public abstract class ReflectionMapStrategyBase : IMapStrategy
|
||||
{
|
||||
private BindingFlags _bindingFlags;
|
||||
|
||||
/// <summary>
|
||||
/// Loops through members with the following BindingFlags:
|
||||
/// Instance | NonPublic | Public | FlattenHierarchy
|
||||
/// </summary>
|
||||
public ReflectionMapStrategyBase()
|
||||
{
|
||||
_bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loops through members with the following BindingFlags:
|
||||
/// Instance | Public | FlattenHierarchy | NonPublic (optional)
|
||||
/// </summary>
|
||||
/// <param name="publicOnly"></param>
|
||||
public ReflectionMapStrategyBase(bool publicOnly)
|
||||
{
|
||||
if (publicOnly)
|
||||
{
|
||||
_bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy;
|
||||
}
|
||||
else
|
||||
{
|
||||
_bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loops through members based on the passed in BindingFlags.
|
||||
/// </summary>
|
||||
/// <param name="bindingFlags"></param>
|
||||
public ReflectionMapStrategyBase(BindingFlags bindingFlags)
|
||||
{
|
||||
_bindingFlags = bindingFlags;
|
||||
}
|
||||
|
||||
public string MapTable(Type entityType)
|
||||
{
|
||||
object[] atts = entityType.GetCustomAttributes(typeof(TableAttribute), true);
|
||||
if (atts.Length > 0)
|
||||
{
|
||||
return (atts[0] as TableAttribute).Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
return entityType.Name;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements IMapStrategy.
|
||||
/// Loops through filtered members and calls the virtual "CreateColumnMap" void for each member.
|
||||
/// Subclasses can override CreateColumnMap to customize adding ColumnMaps.
|
||||
/// </summary>
|
||||
/// <param name="entityType"></param>
|
||||
/// <returns></returns>
|
||||
public ColumnMapCollection MapColumns(Type entityType)
|
||||
{
|
||||
ColumnMapCollection columnMaps = new ColumnMapCollection();
|
||||
|
||||
MemberInfo[] members = entityType.GetMembers(_bindingFlags);
|
||||
foreach (var member in members)
|
||||
{
|
||||
ColumnAttribute columnAtt = GetColumnAttribute(member);
|
||||
CreateColumnMap(entityType, member, columnAtt, columnMaps);
|
||||
}
|
||||
|
||||
return columnMaps;
|
||||
}
|
||||
|
||||
public RelationshipCollection MapRelationships(Type entityType)
|
||||
{
|
||||
RelationshipCollection relationships = new RelationshipCollection();
|
||||
|
||||
MemberInfo[] members = entityType.GetMembers(_bindingFlags);
|
||||
foreach (MemberInfo member in members)
|
||||
{
|
||||
RelationshipAttribute relationshipAtt = GetRelationshipAttribute(member);
|
||||
CreateRelationship(entityType, member, relationshipAtt, relationships);
|
||||
}
|
||||
|
||||
return relationships;
|
||||
}
|
||||
|
||||
protected ColumnAttribute GetColumnAttribute(MemberInfo member)
|
||||
{
|
||||
if (member.IsDefined(typeof(ColumnAttribute), false))
|
||||
{
|
||||
return (ColumnAttribute)member.GetCustomAttributes(typeof(ColumnAttribute), false)[0];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected RelationshipAttribute GetRelationshipAttribute(MemberInfo member)
|
||||
{
|
||||
if (member.IsDefined(typeof(RelationshipAttribute), false))
|
||||
{
|
||||
return (RelationshipAttribute)member.GetCustomAttributes(typeof(RelationshipAttribute), false)[0];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inspect a member and optionally add a ColumnMap.
|
||||
/// </summary>
|
||||
/// <param name="entityType">The entity type that is being mapped.</param>
|
||||
/// <param name="member">The member that is being mapped.</param>
|
||||
/// <param name="columnMaps">The ColumnMapCollection that is being created.</param>
|
||||
protected abstract void CreateColumnMap(Type entityType, MemberInfo member, ColumnAttribute columnAtt, ColumnMapCollection columnMaps);
|
||||
|
||||
/// <summary>
|
||||
/// Inspect a member and optionally add a Relationship.
|
||||
/// </summary>
|
||||
/// <param name="entityType">The entity that is being mapped.</param>
|
||||
/// <param name="member">The current member that is being inspected.</param>
|
||||
/// <param name="relationshipAtt">A RelationshipAttribute (is null if one does not exist).</param>
|
||||
/// <param name="relationships">A list of Relationships.</param>
|
||||
protected abstract void CreateRelationship(Type entityType, MemberInfo member, RelationshipAttribute relationshipAtt, RelationshipCollection relationships);
|
||||
}
|
||||
}
|
43
Marr.Data/Mapping/TableAttribute.cs
Normal file
43
Marr.Data/Mapping/TableAttribute.cs
Normal file
|
@ -0,0 +1,43 @@
|
|||
/* Copyright (C) 2008 - 2011 Jordan Marr
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Marr.Data.Mapping
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
|
||||
public class TableAttribute : Attribute
|
||||
{
|
||||
private string _name;
|
||||
|
||||
public TableAttribute()
|
||||
{
|
||||
}
|
||||
|
||||
public TableAttribute(string name)
|
||||
{
|
||||
_name = name;
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
set { _name = value; }
|
||||
}
|
||||
}
|
||||
}
|
61
Marr.Data/Mapping/TableBuilder.cs
Normal file
61
Marr.Data/Mapping/TableBuilder.cs
Normal file
|
@ -0,0 +1,61 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Marr.Data.Mapping
|
||||
{
|
||||
/// <summary>
|
||||
/// This class has fluent methods that are used to easily configure the table mapping.
|
||||
/// </summary>
|
||||
public class TableBuilder<TEntity>
|
||||
{
|
||||
private FluentMappings.MappingsFluentEntity<TEntity> _fluentEntity;
|
||||
|
||||
public TableBuilder(FluentMappings.MappingsFluentEntity<TEntity> fluentEntity)
|
||||
{
|
||||
_fluentEntity = fluentEntity;
|
||||
}
|
||||
|
||||
#region - Fluent Methods -
|
||||
|
||||
public TableBuilder<TEntity> SetTableName(string tableName)
|
||||
{
|
||||
MapRepository.Instance.Tables[typeof(TEntity)] = tableName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FluentMappings.MappingsFluentColumns<TEntity> Columns
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_fluentEntity == null)
|
||||
{
|
||||
throw new Exception("This property is not compatible with the obsolete 'MapBuilder' class.");
|
||||
}
|
||||
|
||||
return _fluentEntity.Columns;
|
||||
}
|
||||
}
|
||||
|
||||
public FluentMappings.MappingsFluentRelationships<TEntity> Relationships
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_fluentEntity == null)
|
||||
{
|
||||
throw new Exception("This property is not compatible with the obsolete 'MapBuilder' class.");
|
||||
}
|
||||
|
||||
return _fluentEntity.Relationships;
|
||||
}
|
||||
}
|
||||
|
||||
public FluentMappings.MappingsFluentEntity<TNewEntity> Entity<TNewEntity>()
|
||||
{
|
||||
return new FluentMappings.MappingsFluentEntity<TNewEntity>(true);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue