change the constraint name in fluentNhibernate auto mapping alteration - oracle

i'm using oracle with FluentNHibernate automapping with alterations & NHibernate
the problem is how to specify the constraint name by overriding the mapping model??
the generated sql like this:
alter table FirstTable
add constraint FK_VerLongIdentifierLongerThan30Characther
foreign key (FirstTableID)
references SecondTable;
i need to change the "FK_VerLongIdentifierLongerThan30Characther" to smaller identifier by overriding the mapping model like this:
model.Override<SomeClass>(m =>
{
m.HasOne<SomeOtherClass>(c => c.SomeProperty).?????????;
//or
m.????????
}
)

Instead of doing an override for each class with this problem, what I have done is create a mapping convention which would truncate objects with surpass a 30-character naming scheme on foreign keys, has many and many to many relations:
public class OracleIHasManyConvention : IHasManyConvention
{
public void Apply(IOneToManyCollectionInstance instance)
{
var keyName = string.Format(CultureInfo.InvariantCulture, "FK_{0}_{1}",
instance.Member.Name,
instance.EntityType.Name).Truncate(30);
instance.Key.ForeignKey(keyName);
}
}
public class OracleForeignKeyConvention : FluentNHibernate.Conventions.ForeignKeyConvention
{
protected override string GetKeyName(Member property, System.Type type)
{
var name = property == null
? "Id_" + type.Name.ToUnderscoredNaming()
: "Id_" + property.Name.ToUnderscoredNaming();
return name.Truncate(30);
}
}
Then I would call these conventions like this:
var cfg = Fluently.Configure()
.Database(SQLiteConfiguration.Standard.UsingFile("foobar.lite3"))
.Mappings(m => m.AutoMappings.Add(AutoMap.AssemblyOf<Product>()
.Where(a => a.Namespace == typeof (Product).Namespace)
.Conventions.Add<OracleIHasManyConvention>()
.Conventions.Add<OracleForeignKeyConvention>()
.Conventions.Add<OracleGeneralConvention>()
.Conventions.Add<CascadeAllConvention>()
));
Here's the Truncate extension:
public static class StringHelper
{
public static string Truncate(this string text, int endIndex)
{
if (text.Length > endIndex)
{
text = text.Substring(0, endIndex).TrimEnd('_');
}
return text;
}
}
I hope this is useful in any way. :)

Related

Use common linq expression to avoid duplicate of entity to poco

How may I avoid to duplicate the code I use for mapping a database entity to a poco object?
Given this code:
private IQueryable<DummyExtended> Find()
{
return (from dt in Entities.dummy_table
select new DummyExtended
{
Description = dt.table_1.table_2.description,
Dummy = new Dummy
{
Name = d.name,
Notes = d.notes,
HelpText = d.help_text
}
}).AsQueryable();
}
Can I create a common linq expression to be re-used for both methods?
private IQueryable<DummyExtended> Find()
{
return (from dt in Entities.dummy_table
select new DummyExtended
{
Description = dt.table_1.table_2.description,
Dummy = ...???
}).AsQueryable();
}
private IQueryable<DummyAlsoExtended> FindAnother()
{
return (from dt in Entities.dummy_table
select new DummyAlsoExtended
{
InnerHtml = dt.table_html.description,
Dummy = ....??
}).AsQueryable();
}
Example:
public static Expression<Func<dummy_table, Dummy>> EntityToPoco()
{
return d => new Dummy
{
Name = d.name,
Notes = d.notes,
HelpText = d.help_text
};
}
I can't quite get it right
....
Dummy = ExtensionClass.EntityToPoco()
So you have a dummy_table which is a Enumerable or Queryable sequence of objects. Let's assume that the sequence contains objects of class DummyTableElement.
You showed, that if you have a DummyTableElement you know how to convert it into a Dummy object. You want to reuse this function to create other objects like DummyExtended and DummyAlsoExtended. If you want to do this LINQ-alike, it is best to create extension functions for it:
static class DummyTableElementExtensions
{
public static Dummy ToDummy(this TableElement tableElement)
{
return new Dummy()
{
Name = tableElement.name,
Notes = tableElement.notes,
HelpText = tableElement.help_text
};
}
}
Once you have this, you can create similar functions to convert TableElements into DummyExtended and DummyAlsoExtended. They will be one-liners.
In the same extension class:
public static DummyExtended ToDummyExtended(this TableElement tableElement)
{
return new DummyExtended()
{
Description = tableElement.table_1.table_2.description,
Dummy = tableElement.ToDummy(),
};
}
public static DummyAlsoExtended ToDummyAlsoExtended(this TableElement tableElement)
{
return new DummyAlsoExtended
{
InnerHtml = tableElement.table_html.description,
Dummy = tableElement.ToDummy(),
};
}
And once you've got these, you can create extension functions to convert any IQueryable of TableElements:
public static IQueryable<DummyExtended> ToDummyExtended(
this IQueryable<TableElement> tableElements)
{
return tableElements
.Select(tableElement => tableelement.ToDummyExtended();
}
And a similar one-line function for DummyAlsoExtended.
Your Find function and FindAnother function will also be one-liners:
private IQueryable<DummyExtended> Find()
{
return dummy_table.ToDummyExtended();
}
private IQueryable<DummyAlsoExtended> FindAnother()
{
return dummy_table.ToDummyAlsoExtended();
}
I'm not sure why you wanted to use an expression in this. It doesn't seem that DummyExtended and DummyAlsoExtended are really similar, except that they both have a property Dummy.
One reason to parameterize the destination of your find function could be because you want to create anonymous classes in your Find function.
Again, once you've created ToDummy this will be a one-liner:
public static IQueryable<TResult> Find<TSource, TResult>(
this IQueryable<TSource> source,
Expression<Func<TSource, TResult>> resultSelector)
{
return source.Select(sourceElement => resultSelector(sourceElement);
}
Usage would be:
var X = dummy_Table.find(tableElement => new
{
foo = tableElement.CalculateFoo(),
bar = tableElement.CalculateBar(),
Dummy = tableElement.ToDummy(),
});

Trying to save comma-separated list

Trying to save selections from a CheckBoxList as a comma-separated list (string) in DB (one or more choices selected). I am using a proxy in order to save as a string because otherwise I'd have to create separate tables in the DB for a relation - the work is not worth it for this simple scenario and I was hoping that I could just convert it to a string and avoid that.
The CheckBoxList uses an enum for it's choices:
public enum Selection
{
Selection1,
Selection2,
Selection3
}
Not to be convoluted, but I use [Display(Name="Choice 1")] and an extension class to display something friendly on the UI. Not sure if I can save that string instead of just the enum, although I think if I save as enum it's not a big deal for me to "display" the friendly string on UI on some confirmation page.
This is the "Record" class that saves a string in the DB:
public virtual string MyCheckBox { get; set; }
This is the "Proxy", which is some sample I found but not directly dealing with enum, and which uses IEnumerable<string> (or should it be IEnumerable<Selection>?):
public IEnumerable<string> MyCheckBox
{
get
{
if (String.IsNullOrWhiteSpace(Record.MyCheckBox)) return new string[] { };
return Record
.MyCheckBox
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(r => r.Trim())
.Where(r => !String.IsNullOrEmpty(r));
}
set
{
Record.MyCheckBox = value == null ? null : String.Join(",", value);
}
}
To save in the DB, I am trying to do this in a create class:
proxy.MyCheckBox = record.MyCheckBox; //getting error here
but am getting the error:
Cannot implicitly convert 'string' to System.Collections.Generic.IEnumerable'
I don't know, if it's possible or better, to use Parse or ToString from the API for enum values.
I know that doing something like this will store whatever I put in the ("") into the DB, so it's just a matter of figuring out how to overcome the error (or, if there is an alternative):
proxy.MyCheckBox = new[] {"foo", "bar"};
I am not good with this stuff and have just been digging and digging to come up with a solution. Any help is much appreciated.
You can accomplish this using a custom user type. The example below uses an ISet<string> on the class and stores the values as a delimited string.
[Serializable]
public class CommaDelimitedSet : IUserType
{
const string delimiter = ",";
#region IUserType Members
public new bool Equals(object x, object y)
{
if (ReferenceEquals(x, y))
{
return true;
}
var xSet = x as ISet<string>;
var ySet = y as ISet<string>;
if (xSet == null || ySet == null)
{
return false;
}
// compare set contents
return xSet.Except(ySet).Count() == 0 && ySet.Except(xSet).Count() == 0;
}
public int GetHashCode(object x)
{
return x.GetHashCode();
}
public object NullSafeGet(IDataReader rs, string[] names, object owner)
{
var outValue = NHibernateUtil.String.NullSafeGet(rs, names[0]) as string;
if (string.IsNullOrEmpty(outValue))
{
return new HashSet<string>();
}
else
{
var splitArray = outValue.Split(new[] {Delimiter}, StringSplitOptions.RemoveEmptyEntries);
return new HashSet<string>(splitArray);
}
}
public void NullSafeSet(IDbCommand cmd, object value, int index)
{
var inValue = value as ISet<string>;
object setValue = inValue == null ? null : string.Join(Delimiter, inValue);
NHibernateUtil.String.NullSafeSet(cmd, setValue, index);
}
public object DeepCopy(object value)
{
// return new ISet so that Equals can work
// see http://www.mail-archive.com/nhusers#googlegroups.com/msg11054.html
var set = value as ISet<string>;
if (set == null)
{
return null;
}
return new HashSet<string>(set);
}
public object Replace(object original, object target, object owner)
{
return original;
}
public object Assemble(object cached, object owner)
{
return DeepCopy(cached);
}
public object Disassemble(object value)
{
return DeepCopy(value);
}
public SqlType[] SqlTypes
{
get { return new[] {new SqlType(DbType.String)}; }
}
public Type ReturnedType
{
get { return typeof(ISet<string>); }
}
public bool IsMutable
{
get { return false; }
}
#endregion
}
Usage in mapping file:
Map(x => x.CheckboxValues.CustomType<CommaDelimitedSet>();

How do I load an entity from a database where the Composite ID of the record contains a key-property with a null value?

I am reading data from an external organisation using Oracle.DataAccess through the Oracle10g provider. One of the tables has a composite id made up of these fields.
course:
institutioncode: "X11"
coursecode: "N100"
campuscode: "A"
entryyear: 2011
entrymonth: 10
The problem is that the campus code is allowed to be null by the external provider instead of empty. This leads to nHibernate returning collections that contain null references instead of course entities.
Other domain objects will use these fields to refer to this course entity as well, so this is actually used as a key and I can't easily remap to use a surrogate key.
From the source in tag 3.1.0GA, the check that is causing this behavior can be found in Nhibernate.Type.ComponentType.Hydrate(IDataReader rs, string[] names, ISessionImplementor session, object owner). This is always refusing the possibility that a key-property could be null. Could this change to make nullability an option on key-property and key-reference properties?
Failing that, how would you recommend reading this data directly with nHibernate?
NULL values in properties are not supported by design.
There are two ways to deal with this:
Import the data instead of using it raw from the source, adding a proper surrogate key.
Handle that entity without NHibernate.
ok my first comment didnt worked out on References (ManyToOne). So here my alternative solution: a usertype to work around the check.
class CourseMap : ClassMap<Course>
{
public CourseMap()
{
CompositeId()
.KeyProperty(c => c.InstitutionCode)
.KeyProperty(c => c.CourseCode)
.KeyProperty(c => c.CampusCode, key => key.Type(typeof(MyUserType)))
.KeyProperty(c => c.EntryYear)
.KeyProperty(c => c.EntryMonth);
}
}
class MyUserType : IUserType
{
public object Assemble(object cached, object owner)
{
return DeepCopy(cached);
}
public object DeepCopy(object value)
{
return value;
}
public object Disassemble(object value)
{
return DeepCopy(value);
}
public new bool Equals(object x, object y)
{
return object.Equals(x, y);
}
public int GetHashCode(object x)
{
return (x == null) ? 0 : x.GetHashCode();
}
public bool IsMutable
{
get { return false; }
}
public object NullSafeGet(IDataReader rs, string[] names, object owner)
{
var value = NHibernateUtil.String.NullSafeGet(rs, names[0]);
return (value == null) ? string.Empty : value;
}
public void NullSafeSet(IDbCommand cmd, object value, int index)
{
string d = string.IsNullOrEmpty((string)value) ? null : (string)value;
NHibernateUtil.String.NullSafeSet(cmd, d, index);
}
public object Replace(object original, object target, object owner)
{
return DeepCopy(original);
}
public Type ReturnedType
{
get { return typeof(string); }
}
public SqlType[] SqlTypes
{
get { return new[] { SqlTypeFactory.GetString(100) }; }
}
}
class SomeEntityMap : ClassMap<SomeEntity>
{
public EntityMap()
{
Id(e => e.Id).GeneratedBy.Assigned();
References(e => e.Course)
.Columns("InstitutionCode", "CourseCode", "CampusCode", "EntryYear", "EntryMonth")
.Fetch.Join(); // important because we can't rely on values, NULL is invalid value
}
}

Creating linq expression with a subtype restriction

I have this list of type IEnumerable<MyBaseType> for which I am trying to create an extra where-clause to retrieve a specific item in the list. The specific value does only exist on subtype MyFirstType and MySecondType. Not on MyBaseType.
Is it possible to create an expression kind of...
MyList.Where(b => (b is MyFirstType || (b is MySecondType)) && b.SpecificValue == message.SpecificValue);
Above is not working since b is of type MyBaseType and SpecificValue does not exist there. Also note that I do have another subtype MyThirdType that neither has the SpecificValue.
What does work doing what I want is this...
foreach (dynamic u in MyList)
{
if (u is MyFirstType || u is MySecondType)
{
if (u.SpecificValue == message.SpecificValue)
{
//Extracted code goes here
break;
}
}
}
Anyone have an idea how to create an linq expression for the above scenario?
Maybe there is a better solution but as I see it, this could work well enough... If you don't mind performance.
Well then, start by declaring an interface:
public interface IMySpecialType
{
object SpecificValue {get; set;} //you didn't specify what type this is
//all your other relevant properties which first and second types have in common
}
Then, make MyFirstType and MySecondType derive from this interface:
public class MyFirstType : MyBaseType, IMySpecialType
{
//snipet
}
public class MyFirstType : MySecondType, IMySpecialType
{
//snipet
}
Then, filter and cast:
MyList
.Where(b => (b is MyFirstType) || (b is MySecondType))
.Cast<IMySpecialType>()
.Where(b => b.SpecificValue == message.SpecificValue);
//do something
The direct translation of your code to a Linq where clause is
string messageValue = "foo";
var result = baseList.Where(item =>
{
dynamic c = item;
if(item is MyFirstType || item is MySecondType)
{
if( c.SpecificValue == messageValue)
return true;
}
return false;
});
This will require testing the type of the class though and using dynamic - so you might as well cast item to either MyFirstType or MySecondType directly.
An alternative would be using reflection to check if the property exists, using this approach you are not dependent on the actual types of your items as long as they do have the property you are interested in:
string messageValue = "foo";
var result = baseList.Where( item =>
{
var prop = item.GetType().GetProperty("SpecificValue");
if (prop != null && prop.GetValue(item, null) == messageValue)
return true;
else return false;
});
If modifying the class hierarchy is an option you can have you MyFirstType or MySecondType implement an interface that holds the property, then you can use OfType() in your Linq query:
interface ISpecific
{
string SpecificValue { get; set; }
}
class MyFirstType : MyBase, ISpecific
{
public string SpecificValue { get; set; }
}
...
string messageValue = "foo";
var result = baseList.OfType<ISpecific>()
.Where(item => item.SpecificValue == messageValue);
A far more easy way to do that would be to create an interface to mark all your classes having this property SpecificValue. Then it's a child play :
static void Main(string[] args)
{
List<MyBaseType> MyList = new List<MyBaseType>();
ISpecificValue message = new MyFirstType();
MyList.OfType<ISpecificValue>().Where(b => b.SpecificValue == message.SpecificValue);
}
}
class MyBaseType { }
interface ISpecificValue { string SpecificValue { get; set; } }
class MyFirstType : MyBaseType, ISpecificValue
{
public string SpecificValue;
}
class MySecondType : MyBaseType, ISpecificValue
{
public string SpecificValue;
}

Linq expression over a list of derived types

I am trying to write a Linq expression that checks against property in a derived class, but the list is made up of members from a base class. Example code below. The 2nd line of the Process method starting with 'var list' does not compile, but I am not sure what syntax I should use to make it valid?
public class Manager
{
public void Process()
{
Base[] stuff = { new Derived() { Id = "1", Name = "me" } };
var list = stuff.Where<Derived>(d => d.Name == "me");
}
}
public class Base
{
public string Id { get; set; }
}
public class Derived : Base
{
public string Name { get; set; }
}
If you know the list has only Derived, you can use the Cast<T> method:
var list = stuff.Cast<Derived>().Where(d => d.Name == "me");
If there are only some Derived, you can use OfType<T>:
var list = stuff.OfType<Derived>().Where(d => d.Name == "me");
In that case, the non-Derived objects will be skipped.

Resources