EF6 Complaining that unused Model has no Key - c#

I just spent some time resolving the strangest bug, and I can't figure out why it happened. Maybe someone can follow along and shed some light on why...?
tl;dr: lightweight MembershipContext fails due to some completely unrelated object not having and ID field, but only does so when running under MVC: all integration tests that make sure this stuff works correctly... they work correctly.
What I Have:
I have a solution with a number of projects. The pertinent ones are:
LPA.Domain (contains POCOs for business objects/behavior)
LPA.Data (contains EF6 stuff with FluentAPI config and references LPA.Domain)
LPA.Web (contains an MVC project, refs Data and Domain)
This is a very normal setup for us and the project has been in development for some time with no issues.
Within the Data project I have two DbContexts that are used. One, MembershipContext is used only during login and bypasses the user-based audit system to validate the user. The MembershipContext has only three entities: User, UserMembershipDetail and UserRole.
The second, CoreContext has all the normal stuff (including tracking the currently logged in user ID for audit purposes). This has many entities.
What I Did:
Now let's pretend I spend a few days doing some domain-level development. I add handful of classes, set up their db counterparts, build the models (in CoreContext, MembershipContext doesn't change), write integration tests for the models and unit tests for the domain work. All is well. I haven't touched MembershipContext at all.
Part of what I did was add a new class to LPA.Domain to deal with an object called Matter (legal matter). This was to mock up a single method I needed elsewhere, but was not set up in the db (yet). I added an Ignore() on the appropriate entity and will flesh it out later. No biggie, right? All still happening in the CoreContext
What Happened:
I get done with a few days of domain-level development, then go to fire up the LPA.Web project and hit a strange error when trying to log in. Some digging around tells me basically this:
When trying to get from Users in MembershipContext, it's throwing an exception saying that the LPA.Data.Matter EntityType has no key.
A couple confusing things about this:
LPA.Data.Matter is not an object. The Matter object resides in the LPA.Domain.Legal namespace. Presumably this is an internal thing with EF6 as it creates it's own object to deal with things. Ok, I can buy that...
MembershipContext makes no use of Matter at all. The three objects it does make use of have no downstream references (shallow or deep) to the Matter object.
Integration Testing to build/retrieve the MembershipContext.Users works fine! (Users being the offending Entity in the exception) I think this must indicate some different method between how the LPA.Web project is loading the LPA.Data.MembershipContext as opposed to how the test project is, but that doesn't make much sense to me...
This Matter object is used in testing for the domain project and the LPA.Data.CoreContext tests without issue, why does it fail on the Membership and only when using it through an MVC project?
How I Fixed It:
As noted, I added the Matter class as a quick helper on the domain but hadn't fleshed out the storage stuff yet. As such, I had no ID field on the object. The resolution was as simple as adding an ID field.
This resolves the problem, but does not in any way help me understand what went wrong.
For what it's worth, in the MVC project we use a custom user and role provider based on the ExtendedMembershipProvider, which uses a custom repository (that in turn uses the MembershipContext). The instantiation of the MembershipContext is identical between the test and the MVC projects. I can't imagine why they'd act differently.
It's as if something in the MVC project is forcing EF6 to read/validate every object in the Domain class to ensure their validity to a non-existing data model.
Does anyone have the slightest idea why this happened? I'm baffled, myself.

Related

Unit Testing - How to build tests around domain entities with lots of encapsulation and many internal states

Admittedly, very new to Unit Testing right now but I'm wanting to make sure I don't end up with a testing project that ends up being a nightmare to maintain.
The big challenge for me right now is how to test behaviors of an entity when it requires the object to be in a certain state, which is achieved through any number of prior method calls. There are no public setters to properties. I am messing around with SpecimenBuilders in AutoFixture, and have a "default state" object builder that creates the entity using its public constructor, but then I get stuck.
Ideally, I'd like to build off this concept and have other builders that create that same entity type but in other states beyond the default, using the SpecimenBuilder that creates the entity in the default state without having to repeat code, and then calling the method to get the entity to next state. Or maybe I'm off track completely here on what I'm thinking. Perhaps I need to just create custom Object Mothers for all this.
I'm open to any suggestions on the best way to approach things. Thanks so much.

Do I have to really create multiple models?

MS stack developer historically.
I have committed to retooling to the following stack
angular -> ms web.api2 -> C# business objects -> sql server
Being old, I develop the database from requirements and use Codesmith to generate the business logic layer. (yes, I have heard of entity framework. even tried it once).
As I embrace Angular and web API 2
I find that Angular wants me to write a model on the front end. This seems to be just a data structure, I cant even add helper methods to it
So I also often write a class with helper methods that takes an instance of the model. Kind of ugly,but it does marry structure and logic.
I find that Web API2 wants me to write a model. This again seems to be just a data structure. I am exploring the dynamic data type, but really this doesn't buy me much. Instead of writing a class, I'm writing a mapping function.
The question is this:
Is there any way around having 3+ copies of each class spread across the stack?
Codesmith is a very capable code generator... it can gen multiple files... but...
If its just a couple data members, and 3 places, I can copy paste edit and get it done.
Just seems to me that now committing to keeping a data structure in synch in 3 different environments is setting oneself up for a lot of work.
I have spent the last 15 years trying to shove as much code as I can into a framework of inheritable classes so I can keep things DRY.
Am I missing something? Are there any patterns that can be suggested?
[I know this isn't a question tailored for SO, but it is where all the smart people shop. Downvote me if you feel honor bound to do so.]
Not entirely familiar with how CodeSmith generates it's classes, but if they are just plain-old-CLR-objects that serialize nicely, you can have WebApi return them directly to your Angular application. There are purists that will frown upon this, but depending on the application, there may be a justification.
Then, in the world of Angular, you have a few options, again, depending on your requirements/justification, and your application - again, purists will definitely frown upon some of the options.
create classes that match what's coming down from the server (more correct method)
Treat everything as "any", lose type safety, and just access properties as you need them i.e. don't create the model. (obviously less correct method)
find a code generation tool that will explore API end points to determine what they return, and generate your typescript classes for you.
Personally, using Entity Framework, I (manually) create my POCO's for database interraction, have a "view"/DTO class that WebAPI would then send back to the client, and a definition of the object in Typescript, but I am a control freak, and don't like generated code.

project design, am I understanding this correctly

I'm a software developer but always worked on "small" projects/solutions.
Now I'm trying to create an application from scratch on my own, just to stay in touch with new developments and learn new stuff. I'm trying to use everything I've never used before.
So basically that means I'm developing a c# application, using EF core 2.1 and SQL Server.
I've read a lot of articles online and I learned A LOT already. But I'm still confused because everyday I find a new article using a different approach.
I would like the opinion of some other developers on what I've got so far.
First of all I'm used to WinForms so for now I'll use that as my UI. Just because I can get fast results with it. Afterwards I'll try using ASP.NET Core.
I also want to be able to use an other UI and still be able to use the rest of my solution.
I have several projects in my solution:
1. Data: EF Context, DbSets, Migrations
2. Models: EF models, used in EF Context (nothing more then POCO's)
3. DTO: Objects exposed to the UI (again, classes and properties, nothing more)
4. Mapper: "DTO to Model" and "Model to DTO"
5. Services: static classes and static methods/functions using all the above, containing the logic. for example GetCustomer uses the EF context class to read the database, gets the model, maps it to a DTO and returns it.
6. UI: binds to the DTO objects and uses the services for every user "action".
That's it, in a nutshell. But am I on the right track?
I've read a lot about IoC but I'm not there yet, but as far as I understand that has "nothing" to do with the above.
I do have 1 specific question: In WinForms there is validation using the IDataErrorInfo interface and for binding I need the INotifyPropertyChanged logic. Where does this belong? I would say in my DTOs but some say a DTO "can't have" any logic.
I'm sorry for the long "question" but I'll appreciate any input to make sure I understand all of this correctly.
A DTO is usually not intended for presentation. It is intended to send raw data, so they're usually dumb objects and are basically just a bunch of property setters and getters.
A View Model is intended to be sent to a View and a View Model also sends back data to a controller. The ViewModel sometimes takes responsibility for presentation logic.

Migration from EntitySpaces to EntityFramework

Our legacy application is using EntitySpaces for database access but since ES is EoL for several years and is causing some performance issues on our application we're thinking about switching over to EntityFramework.
Is there an easy way to do this without completely rewriting all of our extension classes?
EntitySpaces is alive again and the API has been updated and is far more streamlined. It's a single DLL Nuget install too. What kind of performance issues, I'd love to hear about the issues
https://mikegriffinreborn.github.io/EntitySpaces/
I've been thinking about this for a while. I don't think there is going to be a simple solution to move away from EntitySpaces and move to EntityFramework. But the approach I would, and probably eventually will take, is if you haven't already, add an interface to each of the methods in your Business logic that inherits from the data classes and include every method you need.
Now, add a Database First EF model and create new business-logic classes for each entity/model to inherit from that interface you've made. Then you know every method that requires re-writing in EntityFramework(LINQ/Lambda). It's a slow process but this way you can do the migration over multiple release windows, slowly moving everything over, referencing the new EF business-logic models as-and-when you have time (and of course, any new tables can use EF straight away).

Referencing an Identity user in another context

I'm fairly new to the Entity Framework, and am working on a project that is making use of the Entity Framework 6, Identity 2, Web Api 2 and MVC 5.
In the initial workings of the project, I have created a BusinessConnectionsContext to represent the build of my business models. I left the ApplicationDbContext that gets created automatically to its own devices, up until now. I'm mostly focusing on Web Api 2.
In my solution, I have an assembly for my models, which includes the BusinessConnectionsContext and ApplicationDbContext, an assembly for the Web Api, and an assembly for the Web, using MVC5. Both the WebApi and Web assemblies will make use of the Models assembly.
I've come to a point where I need to link ApplicationDbContext users with the BusinessConnectionsContext, but I can't find any information about this. I get the feeling I'm, perhaps, doing it wrong.
Should all the models in the BusinessConnectionsContext be relocated into the ApplicationDbContext?
It seems a fairly hefty move. What would typically happen if you had otherwise unrelated contexts requiring links into identity in the one system?
The short answer is all the models should be located in the one context. Either stick with the ApplicationDbContext that is created by default, or make your own. So far, I've not seen anything that deals with an Identity model that might be shared between two contexts, and I don't expect that transactions would extend across multiple contexts either.
As for what happens when you have otherwise unrelated contexts requiring links into identity in the one system? I don't know. I could say that you also have the contexts and models in different name spaces, and only use one context at a time, especially when it comes to updates.
One thing, slightly unrelated to the question, was the issue of the ApplicationUserManager, a wrapper for IUserStore.
I had several projects using the one context, but because they all had different expectations of who was accessing the project (one for admin via web, one for users via web and another for special users via webapi), they all had their own ApplicationUserManager. At some point, I had decided to use Unity to make sure the one context was shared across all repositories and the unity of work. I also had to make sure this context was also used in the IOwinContext that was used by the ApplicationUserManager. Since I'm not an expert in such things, I wont go into detail here (I guess it would the answer for another question), but suffice to say, on the subject of context and identity shared between multiple projects, it's something to keep in mind.

Categories