Just trying to confirm an impression: it seems enums in EF5 + Code First are only supported when declared within the same namespace as the classes using them as property types.
Can anyone confirm that? Couldn't find anything on the web for this...
A relevant bug that was fixed earlier. 4.3 Beta 1 release notes say:
Bug fix for GetDatabaseValues. In earlier releases this method would
fail if your entity classes and context were in different namespaces.
This issue is now fixed and the classes don’t need to be in the same
namespace to use GetDatabaseValues.
My guess is that GetDatabaseValues function is still buggy for this occasion (but that's just an educated guess). You may want to report this here: ADO.NET team blog: EF5 Beta 1 Available
Not only do your enumerations have to be in the same namespace to be supported by EF5 Code First, they have to be in the same class file as your POCO Model.
Related
For my specific context I control the target classes. They were auto-generated based on XSDs and have huge overlaps because they represent different versions of the same class.
Each version is a huge C# class of over 5.000 lines.
Support can't be dropped for old versions. This means we always need to be able to map the domain class to several different versions and back again. There are always small but breaking changes from version to version. More than 90% of the target class is always the same, even if the code is duplicated for each version.
Currently there is one big mapping for each format, which is a horror. There is so. much. duplicated. code. Furthermore, developers tend to make updates where they need it, and skip everything else, which means individual versions often go out of sync, meaning that one version will be updated to do something that other versions don't. This is also not ideal.
So my question to you is: What strategy can you use for this kind of mapping?
Given the size of your classes, and having to maintain multiple versions, I'd suggest serializing and serializing. Assuming that they otherwise approximate one another, JsonConvert doing JsonConvert.Deserialize<TargetClass>(JsonConvert.Serialize(sourceClass)) should solve it, though I've not worked with such large models to have any idea on how performant it is.
Alternatively, you could use a t4 template (if you're not in .net Core anyway) to generate the mapping using reflection into a common method or whatever.
As far as preventing the Developer problem... Interfaces, base classes that define as much of this centrally as possible. Code reviews to ensure that developers are making changes to the lowest layer they possibly can.
You can do some tricky things with inheretence with static using statements, I'm pretty sure.
Something dumb like
using OldVersion = path.to.the.class.CantRenameThis;
class CantRenameThis : OldVersion
We ended up with a solution that achieved the main targets:
Decent compile-time safety to spot mapping errors
De-duplication of code
No messing with the auto-generated code
We did this by exploiting that the auto-generated classes are generated as partial. That means we can extend them.
We ended up creating hierarchies of interfaces/classes looking like this:
ClassV1 implements IClassVerySpecificV1
ClassV2 implements IClassVerySpecificV2
IClassVerySpecificV1 implements SpecificA, SpecificB, SpecificC and IClassBasic
IClassVerySpecificV1 implements SpecificB, SpecificC, SpecificD and IClassBasic
A mapper would then look like:
ClassV1Mapper requires a SpecificAMapper, SpecificBMapper, SpecificCMapper and ClassBasicMapper
ClassV2Mapper requires a SpecificBMapper, SpecificCMapper, SpecificDMapper and ClassBasicMapper
This way we could map 90% of everything by just throwing everything that belongs to IClassBasic into a ClassBasicMapper.
We did run into some issues however:
As you can already guess, we end up with a LOT of interfaces. More than you want.
Sometimes a field exists across versions, but has different (enum) values. Our domain model would have the superset, with an attribute specifiying which values were valid for which versions.
I get the error:
Ambiguous match found
During this code on the .Add
var db = new NexusEntities();
db.Reports.Add(mmr);
From googling it appears to be an issue if the there are two classes with the same name but in different namespaces. As far as I can tell this is not the case... Is there another reason why this error can happen? Or is there a way to tell which parameter it is finding two of?
This is a "weakness" in EF. It happens when the same property appears in class / subtype hierarchy.
Most likely you have a hidden field. i.e. a property that has been redefined.
When EF looks for the a property it too must use the type/base tree to find the property. But if it finds it twice in the tree, it interprets this as a duplicate. EF doesnt just use the lowest most specific override.
So property hiding is not possible with EF.
Check your classes, a property will occur twice somewhere.
Although this is probably a much less likely scenario, but we were running EF Core 1.0 which had only one version of the Include() method... in version 1.1, Microsoft added a second implementation (the string version) and since we were calling this method dynamically we got this error after updating our EF Core to 1.1
FxCop analysed the auto-generated code in edmx files...
This bug is already known: Mircosoft Connect.
The only solution proposed there is from 2010 Customizing the Entity Framework T4 Template, suppressing code analysis.
Do you know some better solution or workaround for this problem?
You could try using the DbContext templates instead of ObjectContext.
More info:
DbContext was introduced in EF 4.1 as part of Code First and since EF5 has also become the default generated context for Db/Model-first approaches. It uses POCO entities and simplifies a lot of common tasks, which I find makes my model easier to maintain. It also wraps ObjectContext, so you can still call into that if you need to. Since it generates different code, you'd be avoiding the FxCop warnings you are currently seeing, but of course switching to DbContext would require changes to your application code.
I'm trying to use protobuf .net to serialize an instance of a class which is inherited from a base class. When trying to serialize\deserialize i'm getting an exception about "type not expected". As I already read, adding the protoinclude with the derived type to the base wil solve the problem. BUT, my problem is that I can't add the attribute, since I don't know the types that will derive my base. As I already read, I understand that V2 is going to provide a way to define a type model in order to describe inheritance. So my questions are:
When V2 release will be avilable?
Is there a workaround in the mean time to solve this issue?
Thanks in advance,
Gil
V2 is available both from nuget and google-code (nuget is a few revs ahead IIRC - and both are a little behind the head). There are a few v1 features not yet re-implemented, but for most purposes you won't notice this. They will be re-added in due course.
Re your problem; that is available via MetaType.AddSubType - however, to use that approach you must be able to reproduce the same int identifiers per-subtype in the future - they are important keys and must not change.
RuntimeTypeModel.Default[typeof(SomeType)].AddSubType(7, subType);
There is also DynamicType available on "object" properties - however this has a few kinks with inheritance-based models; I would avoid that for now (this too will be rectified shortly).
I am building a class library and using its default namespace as "System". There suppose I am creating a generic data structure say PriorityQueue and putting it under System.Collections.Generic namespace.
Now when I am referencing that library from another project, I can't see PriorityQueue under "System.Collections.Generic" namespace anymore. Though the library is referenced I can not access any of the classes in it.
Can anyone shed some light on it please. I know that if I change the namespace everything will be ok, but I want to create a seamless integration like .net framework itself with other project, so that one can refer the library and forget about its namespaces.
This is a very bad idea. Pretend you didn't think it up, and use a real namespace.
One does not have "seamless integration" with the .NET Framework, either. If we want to access the List<T> class, then we have to write
using System.Collections.Generic;
If you put your class in MyCompany.Collections.Generic, then you'll get exactly the same level of "seamlessness" that is achieved by the .NET Framework itself.
If you are using the System namespace for your classes, then they will be found in System.
If you want them to be found in System.Collections.Generic, then you need to place them there.
But let's be clear, placing classes in System.* is a bad idea.
Putting stuff in system namespaces is a bad idea. Firstly it's better to know explicitly where the stuff your using is. However more importantly, if Microsoft releases new stuff that causes a naming conflict with yours, your stuff breaks.
The second reason is probably why you cant see your code.
Just create your own namespace, e.g. Anindya.Collections.Generic, as placing classes in predefined framework namespaces isn't a good idea. MS might introduce a same class in a later framework, leading to problems.
Did somebody mention yet that this is a bad idea? There are few reasons you wouldn't be able to see the class. Short from the assembly reference, there is only one good one: you forgot to declare the class public.
In case it wasn't clear: This is a REALLY bad idea.
The System name space should be considered reserved and verboten. If Microsoft decides to introduce a class in a framework update that conflicts with your System.mycrap.blah identifier in the future, you're going to have some pretty hefty refactoring on your hands, and, in the case of an app that's deployed to a client, an emergency update and potential liability for system downtime.
You wouldn't create your own class called "String." By the same token (pun), don't use reserved namespaces.
Also, the namespace "System" doesn't really describe the contents of your namespace. Typically, namespaces should mean something - like, BlogEngine, DatabaseCore, etc. Slapping everything into System is a lot like naming all of your variables "x," or "temp," and implies that the creator doesn't really understand the point of this level of code delineation and organization.