I am creating a Unit Test for a certain method that loads all the types that was decorated by a PluginAttribute.
Instead of manually creating a stub and decorating it with PluginAttribute, is there a way to "inject" an attribute on the Moles generated stub object?
foreach (Type t in types)
{
var attr = Attribute.GetCustomAttribute(t, typeof(PluginAttribute), false) as PluginAttribute;
if (attr != null)
{
_checksLookup.Add(attr.ElementName, t);
}
}
}
Using Moles you can detour the Attribute.GetCustomAttribute method so that it returns a new instance of PluginAttribute when it gets the stub type on input or falls back to the default implementation otherwise.
Related
I want to have a single Mapper class with both create and update methods. The generated code for create method is fine, but in case of update, I want to set the properties in the target, only if they are not null in the source.
How do I do it with mapStruct?
The confusion arises because the nullValueMappingStrategy is being defined at Mapper or Mapping level.
If I set that value at Mapper level, it will be applied to all methods, including create and update.
#Mapper // If I define null strategy here, it will be applied to all methods
public interface AmcPkgMapper {
AmcPkgMapper MAPPER = Mappers.getMapper(AmcPkgMapper.class);
AmcPackage create(AmcPackageRequest amcPackageRequest);
// How to define the null strategy here??
void update(AmcPackageRequest amcPackageRequest, #MappingTarget AmcPackage amcPackage);
}
And if I set it on the method with Mapping, then it expects me to define a target object, for which I probably need a wrapper object and somehow map all the internal properties inside that.
#Mapping(target = "amcPackage", nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
void update(AmcPackageRequest amcPackageRequest, #MappingTarget AmcPackageWrapper amcPackageWrapper);
With the above method, the generated code looks as below, which isn't going inside amcPackage to set all properties.
#Override
public void update(AmcPackageRequest amcPackageRequest, AmcPackageWrapper amcPackageWrapper) {
if ( amcPackageRequest == null ) {
return;
}
// nothing is mapped actually!!
}
Is there a simple way to do it without creating separate mapper classes for create and update?
Got it done with #BeanMapping
#BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE,
nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS)
void update(AmcPackageRequest amcPackageRequest, #MappingTarget AmcPackage amcPackage);
I have an entity framework context with tables EntityTypeA, EntityTypeB ... EntityTypeZ. I would like to create a method which returns an IEnumerable of IEntityModel, or in other words the content of the tables listed above.
I currently have a switch which, based on the type provided as argument, returns the content of the corresponding table.
Please consider the following code that I'm trying to factorize:
IEnumerable<IEntityModel> GetAllEntitiesByType(Type entityType)
{
NorthwindEntities en = new NorthwindEntities();
switch (entityType.Name)
{
case "EntitiesTypeA":
return en.EntitiesTypeA;
// all types in between
case "EntitiesTypeZ":
return en.EntitiesTypeZ;
default:
throw new ArgumentException("Unknown model type: " + entityType);
}
}
I would be surprised if there were no other more concise way to achieve the same result (by using reflection for instance) but I can't seem to find a useful example.
Any ideas please?
You can use the non generic DbContext.Set method to get the corresponding DbSet and then cast it to IEnumerable<IEntityModel> (important - do not use Cast method but regular C# cast operator):
IEnumerable<IEntityModel> GetAllEntitiesByType(Type entityType)
{
NorthwindEntities en = new NorthwindEntities();
return (IEnumerable<IEntityModel>)en.Set(entityType);
}
Consider using generic repository pattern. Here you can find an example.
Then implement the GetAllEntitiesByType function in your repository like this:
IEnumerable<T> GetAllEntitiesByType()
{
return entities.Set<T>();
}
I'd like to generate a List field into my class generated from my DSL and initialize it like this:
private List<MyObject> myObjects= Lists.newArrayList();
The only way I know for this, is to append some text to the initializer:
members += appRule.toField("myObjects", appRule.newTypeRef(List, it.newTypeRef(MyObject))) [
initializer = [append('''Lists.newArrayList()''')]
]
However, using this approach the JvmModelInferrer won't import the Guava Strings library, thus will raise compilation issues. Is there any way to overcome this obstacle?
If I understand your issue (as you are referring to the Guava Strings library that is not used in the code :) ), your problem is, that the class reference Lists is not imported.
For such constructs, we have a helper method in EMF-IncQuery that serializes a type reference the same way parameters are serialized. This functionality relies on the injectable TypeReferenceSerializer class.
def referClass(ITreeAppendable appendable, EObject ctx, Class<?> clazz, JvmTypeReference... typeArgs) {
val ref = ctx.newTypeRef(clazz, typeArgs)
if (ref != null) {
appendable.serialize(ref, ctx)
} else {
//Class resolution error - error handling required here
//A fallback to writing out the fqn of the class
appendable.append(clazz.canonicalName)
}
}
def serialize(ITreeAppendable appendable, JvmTypeReference ref, EObject ctx) {
typeReferenceSerializer.serialize(ref, ctx, appendable)
}
I am using EF5, although I am sure it is a more general EF Question.
I cannot get the following to work. I keep getting casting error:
Unable to cast object of type 'System.Data.Objects.ObjectQuery`1[StdOrgUser]' to type 'System.Data.Objects.ObjectSet`1[StdOrgUser]'.
For the code:
public ObjectSet<StdOrgUser> StdOrgUser
{
get
{
if ((_StdOrgUser == null))
{
_StdOrgUser = base.CreateObjectSet<StdOrgUser>("StdOrgUser");
_StdOrgUser = (ObjectSet<StdOrgUser>) _StdOrgUser.Where(r => r.IsActive == false);
}
return _StdOrgUser;
}
}
It compiles fine. Intellisense enables me to choose LINQ operators etc. It is when I run it, that I get the above runtime error.
Where am I going wrong?
Many thanks for any help.
The ObjectSet class implements (amongst other things) IQueryable and IEnumerable, both of these interfaces have an extension method Where, see here and here. Neither IQueryable nor IEnumerable (which are the respective return types of the extension methods) can be cast back to ObjectSet.
The following line of code cannot be evaluated until run time:
_StdOrgUser = (ObjectSet<StdOrgUser>) _StdOrgUser.Where(r => r.IsActive == false);
but if you remove the cast the code will not compile:
_StdOrgUser = _StdOrgUser.Where(r => r.IsActive == false);
UPDATE
For querying you could change the return type of StdOrgUsers from ObjectSet to IQueryable but you lose all the other methods such as Add, Attach etc. You can't apply a standard filter using this technique. You could have an extension method called ActiveUsers()
public static IQueryable<StdOrgUser> ActiveUsers(this ObjectSet<StdOrgUser> users)
{
return users.Where(r => r.IsActive == false);
}
what you need to do is remember to use it in each query (not very pretty but it does clearly show intent)
var results = myContext
.StdOrgUser
.ActiveUsers()
.Where(//some filter);
My database has a 'LastModifiedUser' column on every table in which I intend to collect the logged in user from an application who makes a change. I am not talking about the database user so essentially this is just a string on each entity. I would like to find a way to default this for each entity so that other developers don't have to remember to assign it any time they instantiate the entity.
So something like this would occur:
using (EntityContext ctx = new EntityContext())
{
MyEntity foo = new MyEntity();
// Trying to avoid having the following line every time
// a new entity is created/added.
foo.LastModifiedUser = Lookupuser();
ctx.Foos.Addobject(foo);
ctx.SaveChanges();
}
There is a perfect way to accomplish this in EF 4.0 by leveraging ObjectStateManager
First, you need to create a partial class for your ObjectContext and subscribe to
ObjectContext.SavingChanges Event. The best place to subscribe to this event is inside the OnContextCreated Method. This method is called by the context object’s constructor and the constructor overloads which is a partial method with no implementation:
partial void OnContextCreated() {
this.SavingChanges += Context_SavingChanges;
}
Now the actual code that will do the job:
void Context_SavingChanges(object sender, EventArgs e) {
IEnumerable<ObjectStateEntry> objectStateEntries =
from ose
in this.ObjectStateManager.GetObjectStateEntries(EntityState.Added
| EntityState.Modified)
where ose.Entity != null
select ose;
foreach (ObjectStateEntry entry in objectStateEntries) {
ReadOnlyCollection<FieldMetadata> fieldsMetaData = entry.CurrentValues
.DataRecordInfo.FieldMetadata;
FieldMetadata modifiedField = fieldsMetaData
.Where(f => f.FieldType.Name == "LastModifiedUser").FirstOrDefault();
if (modifiedField.FieldType != null) {
string fieldTypeName = modifiedField.FieldType.TypeUsage.EdmType.Name;
if (fieldTypeName == PrimitiveTypeKind.String.ToString()) {
entry.CurrentValues.SetString(modifiedField.Ordinal, Lookupuser());
}
}
}
}
Code Explanation:
This code locates any Added or Modified entries that have a LastModifiedUser property and then updates that property with the value coming from your custom Lookupuser() method.
In the foreach block, the query basically drills into the CurrentValues of each entry. Then, using the Where method, it looks at the names of each FieldMetaData item for that entry, picking up only those whose Name is LastModifiedUser. Next, the if statement verifies that the LastModifiedUser property is a String field; then it updates the field's value.
Another way to hook up this method (instead of subscribing to SavingChanges event) is by overriding the ObjectContext.SaveChanges Method.
By the way, the above code belongs to Julie Lerman from her Programming Entity Framework book.
EDIT for Self Tracking POCO Implementation:
If you have self tracking POCOs then what I would do is that I first change the T4 template to call the OnContextCreated() method. If you look at your ObjectContext.tt file, there is an Initialize() method that is called by all constructors, therefore a good candidate to call our OnContextCreated() method, so all we need to do is to change ObjectContext.tt file like this:
private void Initialize()
{
// Creating proxies requires the use of the ProxyDataContractResolver and
// may allow lazy loading which can expand the loaded graph during serialization.
ContextOptions.ProxyCreationEnabled = false;
ObjectMaterialized += new ObjectMaterializedEventHandler(HandleObjectMaterialized);
// We call our custom method here:
OnContextCreated();
}
And this will cause our OnContextCreated() to be called upon creation of the Context.
Now if you put your POCOs behind the service boundary, then it means that the ModifiedUserName must come with the rest of data from your WCF service consumer. You can either expose this
LastModifiedUser property to them to update or if it stores in another property and you wish to update LastModifiedUser from that property, then you can modify the 2nd code as follows:
foreach (ObjectStateEntry entry in objectStateEntries) {
ReadOnlyCollection fieldsMetaData = entry.CurrentValues
.DataRecordInfo.FieldMetadata;
FieldMetadata sourceField = fieldsMetaData
.Where(f => f.FieldType.Name == "YourPropertyName").FirstOrDefault();
FieldMetadata modifiedField = fieldsMetaData
.Where(f => f.FieldType.Name == "LastModifiedUser").FirstOrDefault();
if (modifiedField.FieldType != null) {
string fieldTypeName = modifiedField.FieldType.TypeUsage.EdmType.Name;
if (fieldTypeName == PrimitiveTypeKind.String.ToString()) {
entry.CurrentValues.SetString(modifiedField.Ordinal,
entry.CurrentValues[sourceField.Ordinal].ToString());
}
}
}
Hope this helps.
There is a nuget package for this now : https://www.nuget.org/packages/TrackerEnabledDbContext
Github: https://github.com/bilal-fazlani/tracker-enabled-dbcontext