We are considesing using BreezeJS as analogous solution to our current WCF Ria Services + Silverlight pair. In WCF Ria Services we have client DataContext containing EntitySet instances which get populated with queries.
For example, there we might have three methods on our DomainService described below. Assume also that User is linked to Order as 1-to-many:
public IEnumerable<User> GetFirst10Users(){
//retrieve from DB with EF
return ObjectContext.Users.OrderBy(u => u.Id).Take(10);
}
public IEnumerable<User> GetLast10Users(){
//retrieve from DB with EF
return ObjectContext.Users.OrderByDesc(u => u.Id).Take(10);
}
public IEnumerable<Order> GetOrders(){
//retrieve from DB with EF
return ObjectContext.Orders;
}
As a result we'll have something like this generated for us on client-side:
public class Context{
public EntitySet<User> Users {...};
public EntitySet<Order> Orders {...};
public EntityQuery<User> GetFirst10UsersQuery(){
}
public EntityQuery<User> GetLast10UsersQuery(){
}
public EntityQuery<Orders> GetOrdersQuery(){
}
}
If we execute first two queries, we'll end up having union of their results in Users collection. Executing the third one will give us all orders in Orders collection, but only subset of those will be contained in Navigation collections of User instances on client. It works really well and as Entities get added to Users collection(by query, or by user's action, or by other viewmodel's side effect) those get displayed on UI right away through binding to ObservableCollection wrapper over Users EntitySet.
The same gets reflected on canceling changes, and I don't need to do a lot for that - just providing observable interface.
With BreezeJS and JS particularly, it looks like that I should be subscribing to various events of Breeze and synchronize data with my Kendo UI observable array instance (which is in fact copying data between breeze cache and Kendo UI observable array).
In WCF Ria Services, Context.Users entityset has EntityAdded / EntityDeleted events which makes it possible to handle additions/removals in our ViewModels.
The same events are also available for NavigationCollections, so we might do user.Orders.EntityAdded += ... for example.
So, I'm trying to implement something similar to what we had in WCF Ria Services + Silverlight using Angular + BreezeJS + Kendo UI in TypeScript. I have kind of found analogs for EntityAdded/Deleted events for EntitySet in Breeze but didn't find anything like this for NavigationCollections.
Could someone let me know if the path I'm trying to go with is completely awkward in BreezeJS/KendoUI/Angular world? If no, how do I handle changes in navigation collections in BreezeJS?
Related
I have a requirement to build a Web API for an existing system. There are various agencies throughout the country, and each agency has its own database. All databases are on one single server. All databases are identical in structure. All databases have their own username and password. An agency has one or more users. A user can belong to one or more agencies. There is also one special database which contains a table of all users, a table of all agencies, and user-agencies bridge table.
Currently they are using a traditional Windows desktop application. When a user sets up this Windows program, they log in with a username and password. The system then displays for them a list of all the agencies that they belong to (normally just one, but some "power users" can belong to a few). They pick an agency, and then the program connects to the correct database. For the remainder of the session, everything that the user does will be done on that database.
The client wants to create a web app to eventually replace the Windows program (and the two will be running side by side for a while). One developer is creating the front end in Angular 5, and I am developing the API in ASP .Net Core 2.1.
So the web app will function in a similar manner to the Windows app. A user logs in to the web app. The web app, which consumes my Web API, tells the API which user just logged in. The API then checks which agency(s) this user belongs to from that database that stores that data. The API returns the list of agencies the user belongs to to the web app. There, the user picks an agency. From this point on, the web app will include this Agency ID in the header of all API calls. The API, when it receives a request from the web app, will know which database to use, based on the Agency ID in the header of the request.
Hope that makes sense...
Obviously this means that I will have to change the connection string of the DbContext on the fly, depending on which database the API must talk to. I've been looking at this, firstly by doing it on the controller itself, which worked but would involve a lot of copy-and-paste anti-patterns in all my controllers. So I am trying to move this to the DbContext's OnConfiguring event. I was thinking it'd be best to create a DbContext Factory to create the DbContexts, using the appropriate connection string. I'm just a bit lost though. You see, when the web app calls an end point on the web api (let's say an HTTP GET request to get a list of accounts), this will fire the HttpGet handler in the Accounts controller. This action method then reads the Agency ID header. But this is all happening on the controller.... If I call the DbContext Factory from the DbContext's OnConfiguring() event, it would have to send the Agency ID (which was read in the controller) to the factory so that the factory knows which connection string to create. I'm trying not to use global variables to keep my classes loosely coupled.
Unless I have some service running in the pipeline that intercepts all requests, reads the Agency ID header, and this somehow gets injected into the DbContext constructor? No idea how I would go about doing this...
In summary, I'm a bit lost. I'm not even sure if this is the correct approach. I've looked at some "multi-tenant" examples, but to be honest, I've found them a bit hard to understand, and I was hoping I could do something a bit simpler for now, and with time, as my knowledge of .Net Core improves, I can look at improving the code correspondingly.
I am working on something similar you describe here. As I am also quite at the start, I have no silver bullet yet. There is one thing where could help you with your approach though:
firstly by doing it on the controller itself, which worked but would involve a lot of copy-and-paste anti-patterns in all my controllers.
I took the approach of having a middleware being in charge of swapping the dbconnection string. Something like this:
public class TenantIdentifier
{
private readonly RequestDelegate _next;
public TenantIdentifier(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext httpContext, GlobalDbContext dbContext)
{
var tenantGuid = httpContext.Request.Headers["X-Tenant-Guid"].FirstOrDefault();
if (!string.IsNullOrEmpty(tenantGuid))
{
var tenant = dbContext.Tenants.FirstOrDefault(t => t.Guid.ToString() == tenantGuid);
httpContext.Items["TENANT"] = tenant;
}
await _next.Invoke(httpContext);
}
}
public static class TenantIdentifierExtension
{
public static IApplicationBuilder UseTenantIdentifier(this IApplicationBuilder app)
{
app.UseMiddleware<TenantIdentifier>();
return app;
}
}
Here I am using a self-created http-header called X-Tenant-Guid to identify the tenants GUID. Then I make a request to the global Database, where I do get the connection string of this tenants db.
I made the example public here. https://github.com/riscie/ASP.NET-Core-Multi-Tenant-multi-db-Example (it's not yet updated to asp net core 2.1 but it should not be a problem to do so quickly)
I have a problem when sending Entity Framework-generated entities with navigation properties over WCF. I have a Securities database for storing financial data and two tables inside it:
Stock : Id, Symbol, CompanyName, ExchangeName
Option: Id, StockId, OptionType, Strike
I created an Entity Framework model for this database. Then I created WCF service which exposes generated Stock and Option EF entities to the clients.
My generated entity Stock has navigation property EntityCollection<Option> Options.
When trying to return Stock entity from WCF service to the client, I get an SerializationException: WCF cannot serialize Options navigation property because database connection has been already closed.
I can call Options.Load() method when database connection is opened to fill Options property, but what should I do if I don't want to load full object graph for Stock entity?
I've fought with this one for a while.
First, I turned lazy loading off. But I still had problems with cycles in my object graph.
Then, I put [DataContract(IsReference = true)] tags on all of my entities. That worked, but I still had a lot of performance issues do to a denormalized database.
Finally, I broke down and make dtos and I use AutoMapper to populate them.
One of my coworkers told me to do this from the beginning, and I should have just listened to him. Do yourself a favor and don't make the same mistake that I did.
Edit
I forgot to mention that I had issues deserializing entities that has properties of type ICollection<T>. These will deserialize as arrays. Somehow T[] implements ICollection<T> but Add and Remove will throw exceptions. This was another reason to use DTOs.
With EF5, not sure with EF4, this might work. Change the navigation property setter to private.
public class OptionEntity
{
// properties
// navigation
public virtual StockEntity Stock { get; private set; }
}
I am learning asp.net mvc and went through a great tutorial that demonstrated it. The tutorial also used Entity Framework.
We have our own data access class which I have to use.
I am a little bit confused as to what I need to do to bridge the gap between our class and MVC framework.
For example, in the tutorial, inside of MovieController.cs file, there is a Edit method, that looks like this:
[HttpPost]
public ActionResult Edit(Movie movie)
{
if (ModelState.IsValid)
{
db.Entry(movie).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(movie);
}
If I don't use the Entity framework, what would it look like? Will I still need to use ModelState.IsValid and save the state like it's done
db.Entry(movie).State = EntityState.Modified;
Please advise. A clearly written example of using asp.net mvc without the use of Entity framework would be great.
What I need to know is what role does state play here and whether it is mandatory to use or is it just a part of how the Entity framework operates.
I would re-write this as:
[HttpPost]
public ActionResult Edit(Movie movie)
{
myDBObject.SaveChanges();
return RedirectToAction("Index");
}
Where myDBObject is my custom database access object.
The examples you see out there where controllers use directly some data access framework such as Entity Framework are bad examples. The whole internet is polluted with such stuff. I can hardly look at it without having my eyes hurt. I consider those as bad practices. Data access should be separated and abstracted in a repository. So for example:
public interface IMoviesRepository
{
Movie Get(int id);
void Save(Movie movie);
}
then you could have some implementation of this interface using plain ADO.NET, EF, NHibernate, a remote web service call, some custom ORM or really whatever:
public class MyCustomFrameworkMoviesRepository: IMoviesRepository
{
...
}
and the controller will take this repository interface as constructor argument:
public class MoviesController: Controller
{
private readonly IMoviesRepository _repository;
public MoviesController(IMoviesRepository repository)
{
_repository = repository;
}
public ActionResult Index(int id)
{
var movie = _repository.Get(id);
return View(movie);
}
[HttpPost]
public ActionResult Index(Movie movie)
{
if (!ModelState.IsValid)
{
return View(movie);
}
_repository.Save(movie);
return RedirectToAction("Success");
}
}
and the last part is to configure your dependency injection framework to pass the correct implementation of the repository into the controller. Now as you can see the way the data is fetched is completely decoupled from the controller logic. It is the way it should be. Always try to avoid the strong coupling between the different layers of your application.
And to answer your question about the State property : this is something completely specific to EF, seeing something like this in a controller is a really pity.
And to bring this even further and improve it you would introduce view models. View models are classes which are specifically designed to meet the requirements of a given view. So for example Movie is a domain model. Domain models should never be directly passed to views. Controller actions should never take domain models as action arguments. You should define view models which will contain only what is required by the given view and then perform the mapping between the view models and the domain models. Frameworks such as AutoMapper make this very simple.
hmm.
MVC and entity framework really have nothing to do with each other; they just work well together.
the if (ModelState.IsValid) validates your view model. If you are not using view objects with validators, it's a little pointless; if you are, then it's quite valuable.
inside the if (ModelState.IsValid) brackets, you would take the post data from your web page (usually a view model) and apply it to the object that will persist it to the database. EF is often used because once it's set up, it's fairly easy to maintain, and a lot less code to write.
db.Entry(movie).State = EntityState.Modified;
db.SaveChanges();
are both EF-related. These would need to be replaced by your repository class methods and objects.
return RedirectToAction("Index");
is MVC. Upon successful persistence to your data store, return the control to the index page.
return View(movie);
is used to redirect back to the original view, because something failed validation.
You would still check ModelState.IsValid, but otherwise your code would look like what you have.
This assumes that your model has DataAnnotations attributes on it, though, which is what ModelState.IsValid is using to check. Those attributes can be used on any C# class' properties - not just Entity Framework.
You might end up creating specific view models for this purpose.
You need to make some connection between the Movie object (passed in on the http POST) and your database methods (myDBObject).
Maybe you want to say myDBObject.SaveChanges(movie) and assuming your db code knows how to handle the object Movie then you'll be fine.
I am working on an app where I am using WCF RIA services and entity framework.
On laod,i have written a method which gets a list of schedules from database(as fetched using RIA method LoadOperation<>).
I have put a breakpoint on the method,but when I debug it the list shows 0 count and when I bind the empty list to datagrid,the grid shows all records.
How's this possible.
I got stuck in between
Kindly help for the same!!!
Loading data via the DomainContext is an asynchronous operation. Binding to a grid, etc. works because LoadOperation.Entities is observable and will fill in eventually. However, if you're trying to access it in code, you will have to wait for the callback.
myContext.Load(myContext.GetMyQuery(), OnLoadCompleted, null);
private void OnLoadCompleted(LoadOperation<MyEntity> op)
{
if (op.HasError)
{
// Handle error
op.MarkErrorAsHandled();
}
else
{
IEnumerable<MyEntity> entities = op.Entities;
// now do stuff with entities
}
}
See this page for more information.
I'm using a distributed web application, with a database server housing the SQL Server 2005 database, an application server where we've installed a Microsoft Three Tier Service Application, and a web server where I using MVP with supervising controller.
My service layer, on the application server, returns an IEnumerable<Country> when I request a list of let's say countries. The service layer calls the data access component, which yields entities like this:
public virtual IEnumerable<T> FillList(DbCommand command, DataContext context)
{
using (IDataReader dataReader = this.ExecuteReader(command, context))
{
while (dataReader.Read())
{
T entity = this.Fill(dataReader, context);
yield return entity;
}
}
}
I'm now a little bit concerned about the connection to my database, as it will remain open when I serialize entities through WCF to my controller. My first question is if this is really a concern to leave my database connection open when serializing entity by entity to my controller? The advantage of this solution is that I can use LINQ even over large collections (not LINQ to SQL).
I came up with this solution: in the service layer, I always return a List, like this:
public virtual List<T> GetList()
{
List<T> list = new List<T>();
list.AddRange(this.dataAccess.GetList()));
return list;
}
But here I'm returning a full list to the controller, and perhaps I only need a few of the items from the list. My second question is if this is a good design?
Look forward to your suggestions!
I don't see any particular problems with the design.
Of course, you'll want to be careful about what the T is in List<T>. Don't return a list of objects with all sorts of behaviors, and don't return types specific to .NET - DataSet and DataTable are a bad idea, for instance. Use simple classes with properties of primitive types, lists and arrays of primitive types, lists and arrays of these simple classes, etc.