I understand that in NHibernate, using mapping by code, I can specify the precision and scale of a decimal property like so:
Property(
x => x.Dollars,
m =>
{
m.Precision(9);
m.Scale(6);
}
);
That is nice, but I was wondering if there was a way that I could easily map ALL of the decimal properties in all of the classes in an easy way. It seems kind of crazy that I would have to go through all of my mappings and update each of them by hand. Does anyone know how this can be achieved ?
Use the BeforeMapProperty on the ModelMapper:-
var mapper = new ModelMapper();
mapper.BeforeMapProperty += (inspector, member, customizer) => {
if (member.LocalMember.GetPropertyOrFieldType() == typeof (decimal))
{
customizer.Precision(9);
customizer.Scale(6);
}
};
The only other thing to add is remove all occurrences of:-
m => { m.Precision(9); m.Scale(6); }
from your mapping classes as these will override your convention set in BeforeMapProperty unless you have other decimals that have different scales or precisions.
You could write a UserType. The advantage is that you could easily distinguish different types of decimals (you most probably don't want to have the same precision for all decimals).
Property(
x => x.Dollars,
m => m.Type<MoneyUserType>()
);
You have some effort to put this into all monetary properties, but then you have a more readable and self descriptive mapping definition.
A similar solution (syntactically), but easier to implement, is to write an extension method which sets up the precision.
Property(
x => x.Dollars,
m => m.MapMoney()
);
public static void MapMoney(this IPropertyMapper mapper)
{
m.Precision(9);
m.Scale(6);
}
Same here: it makes the mapping definition more self descriptive.
(Yes I know that you don't want to change all the files, but I still recommend to put this information into the mapping files, because it is more explicit what the decimal actually is. It is very easy to change the mapping for all Money properties, but keep the Amount properties. For the completely implicit solution, read on.)
Alternatively you could use mapping conventions. These is very powerful. You still can overwrite the precision in the mapping file, which provides great flexibility.
mapper.BeforeMapProperty += MapperOnBeforeMapProperty;
private void MapperOnBeforeMapProperty(
IModelInspector modelInspector,
PropertyPath member,
IPropertyMapper propertyCustomizer)
{
Type propertyType;
// requires some more condition to check if it is a property mapping or field mapping
propertyType = (PropertyInfo)member.LocalMember.PropertyType;
if (propertyType == typeof(decimal))
{
propertyCustomizer.Precision(9);
propertyCustomizer.Scale(6);
}
}
It is also possible to put the user type into the mapping convention, as a default.
Can you use FluentNHibernate? It enables you to apply conventions with as much flexibility as you need. See here: https://github.com/jagregory/fluent-nhibernate/wiki/Conventions and here: http://marcinobel.com/index.php/fluent-nhibernate-conventions-examples/ where it has this particular example:
public class StringColumnLengthConvention
: IPropertyConvention, IPropertyConventionAcceptance
{
public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)
{
criteria.Expect(x => x.Type == typeof(string))
.Expect(x => x.Length == 0);
}
public void Apply(IPropertyInstance instance)
{
instance.Length(100);
}
}
This looks like you could easily adapt to map all decimals like he does with strings.
Related
I'm creating unit tests in which I will be comparing lists of objects with one another.
Currently I am using Fluent assertions in combination with specflow and nunit. I already use the Fluent Assertions to make a comparison as following:
public void TestShizzle()
{
// I normally retrieve these lists from a moq database or a specflow table
var expected = list<myObject>
{
new myObject
{
A = 1,
B = "abc"
}
}
var found = list<myObject>
{
new myObject
{
A = 1,
B = "def"
}
}
// this comparison only compares a few columns. The comparison is also object dependent. I would like to make this dynamic
found.Should().BeEquivalentTo(
expected,
options =>
options.Including(x => x.A));
}
What I really want is to be able to use generics instead of a specified type. I also want to decide which properties to compare at compile time. This is because of the large number of tables in the database. I think i need to use Linq Expressions for this, but I don't know how to go about this. The function should look something like this:
public void GenericShizzle<T>(List<T> expected, List<T> found, IEnumerable<PropertyInfo> properties)
{
Expression<Func<T, object>> principal;
foreach(var property in properties)
{
// create the expression for including fields
}
found.Should().BeEquivalentTo(
expected,
options =>
// here is need to apply the expression.
}
I have no real idea how to get the correct expression for the job, or if this even the best method. I think I need to create an property expression that is understood by the include function, but maybe a different method can be used?
There is Including method overload accepting Expression<Func<IMemberInfo, bool>> which can be used to dynamically filter members based on information about them:
IEnumerable<PropertyInfo> properties = ...;
var names = properties
.Select(info => info.Name)
.ToHashSet();
found.Should()
.BeEquivalentTo(expected,
options => options.Including((IMemberInfo mi) => names.Contains(mi.Name))); // or just .Including(mi => names.Contains(mi.Name))
In NHibernate they had a nifty little concept of a convention, where you could say, if an entity had a Name property, and it was a string, you could apply certain db behavior to it (for example, set it to not null, max length x, maybe unique if you could be certain all names would be unique).
It would be a small class, you'd add it to your instance factory, and bam! The db model would build accordingly.
Is there a comparable mechanism in EF Core? I can't seem to find any and the ridiculous number of fluent configurations for every entity for every property is quite tedious.
In EF Core the built-in conventions are used to create an initial model, which you can override or modify in OnModelCreating.
You can simply iterate over your entities and properties override the conventions. This works well enough in place of custom conventions from EF6 that (at least so far) custom conventions haven't made it off the backlog. See https://github.com/aspnet/EntityFrameworkCore/issues/214 for status and some examples. It's also a pretty common pattern to read a custom attribute in OnModelCreating to drive (or override) your entity configuration.
So your example:
if an entity had a Name property, and it was a string, you could apply certain db behavior to it (for example, set it to not null, max length x, maybe unique if you could be certain all names would be unique).
would be something like:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var props = from e in modelBuilder.Model.GetEntityTypes()
from p in e.GetProperties()
where p.Name == "Name"
&& p.PropertyInfo.PropertyType == typeof(string)
select p;
foreach (var p in props)
{
p.SetMaxLength(200);
p.IsNullable = false;
p.DeclaringEntityType.AddKey(p);
}
base.OnModelCreating(modelBuilder);
}
Or if you wanted to force the datatypes for all DataTime columns, something like:
var dateProps = from e in modelBuilder.Model.GetEntityTypes()
from p in e.GetProperties()
where p.PropertyInfo.PropertyType == typeof(DateTime)
select p;
foreach (var prop in dateProps)
{
prop.Relational().ColumnType = "datetime2(4)";
}
I regularly find myself coding things like
int? min = someQueryable
.Where(x => someCondition)
.Select(x => (int?)x.someNonNullableIntProperty)
.Min();
It allows me to get null instead of "System.ArgumentNullException: value cannot be null" when nothing matches the condition. (And I do not want to get 0 instead of null.)
I would like to avoid the cast. Is there any other way I have missed?
The hard part is, it should be of sufficiently common use to be natively understood (or ignored) by linq providers. (linq-to-entities and linq-to-nhibernate for my specific needs.)
Otherwise I would have to add some custom AsNullable extensions to linq-to-nh provider (which requires some work), and I do not know if EF (6) allows to do this.
Why do I wish avoiding cast? Casting may go unnoticed during refactoring, and then may cause bugs. And most of the cast I see in code are due to careless developers, not trying to memorize they can have the non-null value from .Value on nullable types, by example. (There is also the ternary case like someCondition ? someIntProperty : (int?)null but the "Elvis" operator ?. will probably allow to avoid most of them ; and we can also write default(int?), althougth it is a bit lengthy. ?. could maybe even be used for my example query, but it would not be a general solution.)
Trying new Nullable<int>(x.someNonNullableIntProperty) as suggested here fails with a NotSupportedException (with NH, not tested with EF). Anyway, it would not suit me either. In case of some later type change of the property, it may go unnoticed too due to implicit conversion. (And trying new Nullable(x.someNonNullableIntProperty) does not compile, generic type argument inferring does not work well with constructors.)
Trying x.someNonNullableIntProperty as int? (which is still a cast, but less tolerant about types mismatch in this case, see this here) fails with an ArgumentException (NH tested again, Expression of type 'System.Int32' cannot be used as a 'System.Nullable`1[System.Int32]' return type (translated)).
I tried this once, but for IEnumerable, and came up with
public static T? max<T>(IEnumerable<T> values) where T: struct, IComparable<T>
{
T? result = null;
foreach (var v in values)
if (!result.HasValue || (v.CompareTo(result.Value) > 0))
result = v;
return result;
}
To handle IQueryable, you'd need to extend your data access library. In case of NHibernate, the mechanism is called HqlGenerator. See this answer for links.
For Entity Framework, I have given up. It looks as too much effort for me. (See here.)
For NHibernate, I have done the AsNullable extension I was thinking of.
This is following the same logic as my other extensions here and here.
First, define an AsNullable extension:
public static class NullableExtensions
{
public static T? AsNullable<T>(this T value) where T : struct
{
// Allow runtime use.
// Not useful for linq-to-nhibernate, could be:
// throw NotSupportedException();
return value;
}
}
Then, implements its HQL translation (originally based on NHibernate compare implementation, then quite simplified, see edits):
public class AsNullableGenerator : BaseHqlGeneratorForMethod
{
public AsNullableGenerator()
{
SupportedMethods = new[]
{
ReflectionHelper.GetMethodDefinition(() => NullableExtensions.AsNullable(0))
};
}
public override HqlTreeNode BuildHql(MethodInfo method,
Expression targetObject,
ReadOnlyCollection<Expression> arguments,
HqlTreeBuilder treeBuilder,
IHqlExpressionVisitor visitor)
{
// Just have to transmit the argument "as is", HQL does not need a specific call
// for null conversion.
return visitor.Visit(arguments[0]).AsExpression();
}
}
Extend the default linq2NH registry with your generator:
public class ExtendedLinqToHqlGeneratorsRegistry :
DefaultLinqToHqlGeneratorsRegistry
{
public ExtendedLinqToHqlGeneratorsRegistry()
: base()
{
this.Merge(new AsNullableGenerator());
}
}
Now configure NH to use your new registry. With hibernate.cfg.xml, add following property node under session-factory node:
<property name="linqtohql.generatorsregistry">YourNameSpace.ExtendedLinqToHqlGeneratorsRegistry, YourAssemblyName</property>
Or using code:
using NHibernate.Cfg;
// ...
var cfg = new Configuration();
cfg.LinqToHqlGeneratorsRegistry<ExtendedLinqToHqlGeneratorsRegistry>();
// And build the session factory using this configuration.
Now we can rewrite the query.
int? min = someQueryable
.Where(x => someCondition)
.Select(x => x.someNonNullableIntProperty.AsNullable())
.Min();
[The question is similar to this: What is the difference between passing It.IsAny<int>() and the value of It.IsAny<int>() to a method setup - needing additional clarification]
Short version
(More definitions below)
I am in a situation where I need to setup mocks in a factory. Depending on the value, I want to choose between using it or It.IsAny<TTypeOfValue>().
This is what I (naively) wanted to do:
moq.Setup(() => mockWebService.WebServiceMethod(
webServiceMethodObject.Some ?? It.IsAny<string>(), // that fails
...,
out webServiceMethodObject.That,
...)).Returns(webServiceMethodObject.ReturnEnum);
I have such large parameterlists (old legacy webservice methods) and so much different combination of values that I don't want to write it by hand, nor using It.IsAny<T>() everywhere, as I want to control the return value depending on parameters.
A possible alternative should be the version, where I could match concrete values with concrete return types, and when no concrete values can be matched, it falls back to the broadest version (with all parameters substituted with It.IsAny<T>(). (Short example: in a login test I'd like to test different return values of different input parameters of a login method. In all other tests I'd just like to return LoginSuccess).
How can I achieve this? Only with some Expression/Reflection magic?
Longer explanation
This is how our typical legacy webservice looks like:
ReturnValueEnum WebServiceMethod(string some, int thing, ..., out int that, out byte[] those, ...) { ... }
We had so many webservice method calls needed and they are so bloated with parameters, that we had to come up with encapsulating them in objects.
Example:
public class WebServiceMethodObject
{
public string Some { get; set; }
public int Thing { get; set; }
...
public ReturnValue ReturnEnum { get; set; }
}
The strategy should be this: we are creating a default version of this object. In the tests we fill up values that needed to be matched. We would like to pass the object to a to-be-written method, which sets up the mock accordingly:
if a property is set: use that value
else: use It.IsAny<T>() (see the Setup above!).
I would've thought that if
webServiceMethodObject.Some ?? It.IsAny<string>()
is what you want but doesn't work, the simple substitution would be
It.Is<string>(v =>
webServiceMethodObject.Some == null ||
webServiceMethodObject.Some == v)
If the logic for the parameters is so complex you can safely use It.IsAny<T> for all parameters and define a custom delegate to process the method call:
moq
.Setup(() => WebServiceMethod(It.IsAny<string>(), It.IsAny<int>(), ...))
.Returns((some, thing, ...) => {
if (some == webServiceMethodObject.Some || webServiceMethodObject.Some == null) ...
{
return webServiceMethodObject.ReturnEnum;
}
});
If you look into the list of Returns overloads you see that there is a wealth of options, the "hardcoded" .Returns(some value) being only one of those.
As far as I know the the whole thing passed to setup is an expression tree. Moq then inspects the expression subtrees for the parameters. If they are It based expressions they are used for advanced logic. If not they are evaluated and the value is matched with the input. This is probably the/one reason why your naïve version is not working.
I want to search through all classes in a namespace for those containing a certain method. If a class contains a method then I want to create an instance of the class and run the method.
Obviously I have to start with reflection but I'm stuck on where to go.
Edit:
Interfaces are not the way I want to do this.
What I'm looking for is embedding testing functions into the code but a single calling interface. If there's a self-test function, call it. If there isn't, ignore it.
Create an interface that declares the method and then have various classes implement that interface.
You can then use reflection to find all types within an assembly that implement that interface.
From there you'll need to create an instance of each type and then call the method. The implementation details will vary depending on what you are trying to do.
Update based on comments:
I still think an interface (or attribute) is the way to go. This is how it would work with an interface.
interface ISelfTester
{
void SelfTest();
}
class SomeClass : ISelfTester
{
/* ... */
public void SelfTest()
{
// test code
}
/* ... */
}
You could then invoke each type's SelfTest method like so (borrowing from Dathan and Darren Kopp):
var type = typeof(ISelfTester);
var types = AppDomain.CurrentDomain.GetAssemblies()
.Select(x => x.GetTypes())
.SelectMany(x => x)
.Where(x => x.Namespace == "My.Name.Space" && type.IsAssignableFrom(x));
foreach (Type t in types)
{
ISelfTester obj = Activator.CreateInstance(t) as ISelfTester;
obj.SelfTest();
}
Without more information about what distinguishes the method, I'm just going to assume it's distinguished by name, and it's public. The name assumption is dangerous, so I wouldn't recommend doing this, but the following should do what you want (assuming Activator is able to create an instance).
EDIT: Added Where(x => x.Namespace == "My.Name.Space") to limit the results to a single target namespace.
EDIT: Added if ... else to handle the case of static methods.
var methods = AppDomain.CurrentDomain.GetAssemblies()
.Select(x => x.GetTypes())
.SelectMany(x => x)
.Where(x => x.Namespace == "My.Name.Space")
.Where(c => c.GetMethod("MethodName") != null)
.Select(c => c.GetMethod("MethodName"));
foreach (MethodInfo mi in methods)
{
if (mi.IsStatic)
{
mi.Invoke(null, null); // replace null with the appropriate arguments
}
else if (!mi.DeclaringType.IsAbstract)
{
var obj = Activator.CreateInstance(mi.DeclaringType);
mi.Invoke(obj, null); // replace null with the appropriate arguments
}
}
If you have control over the types, though, jrummel's suggestion about interfaces is a much safer way to do this.
One option would be to use Reflection, as described above, but rather than finding the method by name, look for a method tagged with an appropriate custom attribute. This is similar to what the MS DataContractSerializer does with attributes like [OnDeserializing]. This way the class implementer is specifically spelling out their intent for the method, rather than having it suddenly do something unexpected as a result of it having a particular name.
On a side note, since what you're after is a test method, you might check out something like NUnit. There are several excellent free unit testing frameworks out there. They also provide additional features that can help with your testing, as they provide the scaffolding for the different types of test assertions you might want to make.