how should i load the table "Setting" into an asp.net mvc so that i can use it as a reference setting for the whole application.
Is there anyway to save the memory and usage to do this problem? In my understanding, if i have settings in database, i will have to make the program load the table into a variable, then call out. But is there anyway to save a query from being waste?
im using linq to sql
Thanks
Yes, if you use a proper ORM layer, like NHibernate (for instance with Fluent), which can cache the calls (SQL queries) to the settings table for you fully automatically. And you'll handle the tables without any SQL, only as calls to methods of classes.
However, it requires learning NHibernate, which can take a bit getting used to.
It is not possible to get the data of the Settings table from the database without issuing a query to the database. But you can prevent the tedious use of mapping the result to objects by using an ORM.
If you take both NHibernate and FluentNHibernate, it looks something like this for MS SQL Server 2008:
// this depends on your implementation, I assume a Settings class with
// simple getters and setters that map directly to the table. Use
// Fluent to do the mapping (see link) automatically through AutoMappings
// example of using AutoMappings plus configuration of linking to DB:
ISessionFactory sessionFactory = Fluently.Configure()
.Database(
MsSqlConfiguration.MsSql2008
.ConnectionString(c =>
c.Server("123.12.21.321")
.Database("db_name")
.Username("db_user_with_access_to_db")
.Password("passwordhere")
)
)
.Mappings(m =>
m.AutoMappings.Add(AutoMap.AssemblyOf<Logo>()
.Where(t => t.Namespace == "YourNamespace.Entities"))
)
.BuildSessionFactory();
// example of a Settings class:
public class Settings
{
public int Id { get; private set; }
public int BackgroundColor { get; set }
// etc
}
// example of getting a session, retrieving data, changing/saving data
ISession session = sessionFactory.OpenSession(); // session for getting data from DB
Setting mySetting = session.Get<Setting>(someId);
mySetting.BackgroundColor = 0xAA44DD;
var transaction = session.BeginTransaction();
session.SaveOrUpdate(mySetting);
transaction.Commit();
// how it looks like if you use Generics and a little Dao class to wrap it all up:
Dao<Settings> daoSettings = new Dao<Settings>();
Settings someSettings = daoSettings.Get(someIdHere);
Settings userSettings = daoSettings.Get(new User("John"));
List<Settings> allSettings = daoSettings.GetAll();
int BackgroundColor = userSettings.BackgroundColor; // any of the columns here
userSettings.BackgroundColor = 0x45DA8E;
daoSettings.Save(userSettings);
Other ORMs exist, NHibernate may be a bit overkill if this is a one-time only situation and if you never did this before. However, it has an automatic level-1 and level-2 cache to prevent any unnecessary roundtrips to the database. It is currently (allegedly?) the industry leading open source ORM solution.
Update: added simple code example and links to NH/Fluent
Related
I'm new using entity framework, and I'm trying to insert into the DB.But I'm having an issue, because I need to only SaveChanges from objects of other 3 scopes. Like this:These are my three Actions that Add the objects into my entities:
public void AddEndereco(entidade_endereco entEndereco)
{
db.entidade_endereco.Add(entEndereco);
}
public void addContato(entidade_contato entContato)
{
db.entidade_contato.Add(entContato);
}
public void addBanco(entidade_banco entBanco)
{
db.entidade_banco.Add(entBanco);
}
And in this action I need to insert all the objects into my DB:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(entidade entidade, string Grupo, string Situacao)
{
if (ModelState.IsValid)
{
if (Grupo != "")
entidade.gre_codigo = Convert.ToInt32(Grupo);
if (Situacao != "")
entidade.sie_codigo = Convert.ToInt32(Situacao);
if (entidade.ver_ativo)
entidade.ent_ativo = "S";
else
entidade.ent_ativo = "N";
if (entidade.ver_cliente)
entidade.ent_cliente = "S";
else
entidade.ent_cliente = "N";
if (entidade.ver_fornecedor)
entidade.ent_fornecedor = "S";
else
entidade.ent_fornecedor = "N";
//ADDING ANOTHER OBJECT
db.entidades.Add(entidade);
//HERE IS WHERE I NEED TO SAVE ALL (entidade_endereco, entidade_contato, entidade_banco, entidade)
db.SaveChanges();
return RedirectToAction("Index");
}
return View(entidade);
}
But it is only saving the entidade object, the others don't exist anymore when db.SaveChanges() is executed.
How can I insert into the DB with objects that were added to my entity in other scopes?
If you really want to make this work as is, you would need to store either the Context (really bad idea) or Entities (slightly less bad) across requests. Session State jumps to mind, but using it can bring in a whole load of new pain.
Ideally, you should change your design to take advantage of the stateless nature of HTTP. Each action method should be a separate transaction, saving the data from it's execution when the method is done. If those separate entities only make sense when they are all saved together, then you need to create all of them within a single action and save them to the context together. Managing the boundaries of different business entities and when they are saved is a critical part of application design, I highly recommend you read about Aggregate Roots within Domain Driven Development. Even if you don't go the full DDD route, the Aggregate Root concept will be extremely helpful to you. The CQRS Journey from Microsoft gives an in-depth tutorial of these concepts (and many others)
Im not sure, if I got your question right (excuse my poor spanish). In the Action Create you only add "entidade" to your entidades collection, and so its the only one affected by SaveChanges(). If you want to add others, include in the Create-Action or try making a EF-transaction.
Without transaction the context is lost after the Create-Method ends
I'm trying to use NHibernate for a new app with a legacy database. It's going pretty well but I'm stuck and can't find a good solution for a problem.
Let's say I have this model :
a Service table (Id, ServiceName..)
a Movie table (Id, Title, ...)
a Contents table which associates a service and a movie (IdContent, Name, IdMovie, IdService)
So I mapped this and it all went good. Now I can retrieve a movie, get all the contents associated, ...
My app is a movies shop "generator". Each "service" is in fact a different shop, when a user enter my website, he's redirected to one of the shops and obviously, I must show him only movies available for his shop. The idea is : user comes, his service is recognized, I present him movies which have contents linked to his service. I need to be able to retrieve all contents for a movie for the backoffice too.
I'm trying to find the most transparent way to accomplish this with NHibernate. I can't really make changes to the db model.
I thought about a few solutions :
Add the service condition into all my queries. Would work but it's a bit cumbersome. The model is very complex and has tons of tables/queries..
Use nhibernate filter. Seemed ideal and worked pretty good, I added the filter on serviceid in all my mappings and did the EnableFilter as soon as my user's service was recognized but.. nhibernate filtered collections don't work with 2nd lvl cache (redis in my case) and 2nd lvl cache usage is mandatory.
Add computed properties to my object like Movie.PublishedContents(Int32 serviceId). Probably would work but requires to write a lot of code and "pollutes" my domain.
Add new entities inheriting from my nhibernate entity like a PublishedMovie : Movie wich only presents the contextual data
None of these really satisfies me. Is there a good way to do this ?
Thanks !
You're asking about multi-tenancy with all the tenants in the same database. I've handled that scenario effectively using Ninject dependency injection. In my application the tenant is called "manual" and I'll use that in the sample code.
The route needs to contain the tenant e.g.
{manual}/{controller}/{action}/{id}
A constraint can be set on the tenant to limit the allowed tenants.
I use Ninject to configure and supply the ISessionFactory as a singleton and ISession in session-per-request strategy. This is encapsulated using Ninject Provider classes.
I do the filtering using lightweight repository classes, e.g.
public class ManualRepository
{
private readonly int _manualId;
private readonly ISession _session;
public ManualRepository(int manualId, ISession session)
{
_manualId = manualId;
_session = session;
}
public IQueryable<Manual> GetManual()
{
return _session.Query<Manual>().Where(m => m.ManualId == _manualId);
}
}
If you want pretty urls you'll need to translate the tenant route parameter into its corresponding database value. I have these set up in web.config and I load them into a dictionary at startup. An IRouteConstraint implementation reads the "manual" route value, looks it up, and sets the "manualId" route value.
Ninject can handle injecting the ISession into the repository and the repository into the controller. Any queries in the controller actions must be based on the repository method so that the filter is applied. The trick is injecting the manualId from the routing value. In NinjectWebCommon I have two methods to accomplish this:
private static int GetManualIdForRequest()
{
var httpContext = HttpContext.Current;
var routeValues = httpContext.Request.RequestContext.RouteData.Values;
if (routeValues.ContainsKey("manualId"))
{
return int.Parse(routeValues["manualId"].ToString());
}
const string msg = "Route does not contain 'manualId' required to construct object.";
throw new HttpException((int)HttpStatusCode.BadRequest, msg);
}
/// <summary>
/// Binding extension that injects the manualId from route data values to the ctor.
/// </summary>
private static void WithManualIdConstructor<T>(this IBindingWithSyntax<T> binding)
{
binding.WithConstructorArgument("manualId", context => GetManualIdForRequest());
}
And the repository bindings are declared to inject the manualId. There may be a better way to accomplish this through conventions.
kernel.Bind<ManualRepository>().ToSelf().WithManualIdConstructor();
The end result is that queries follow the pattern
var manual = _manualRepository
.GetManual()
.Where(m => m.EffectiveDate <= DateTime.Today)
.Select(m => new ManualView
{
ManualId = m.ManualId,
ManualName = m.Name
}).List();
and I don't need to worry about filtering per tenant in my queries.
As for the 2nd level cache, I don't use it in this app but my understanding is that you can set the cache region to segregate tenants. This should get you started: http://ayende.com/blog/1708/nhibernate-caching-the-secong-level-cache-space-is-shared
I am learning MVC4 in Visual Studio and I have many questions about it. My first statement about MVC is that MVC's Model doesnt do what I expected. I expect Model to select and return the data rows according to the needs.
But I read many tutorial and they suggest me to let Model return ALL the data from the table and then eliminate the ones I dont need in the controller, then send it to the View.
here is the code from tutorials
MODEL
public class ApartmentContext : DbContext
{
public ApartmentContext() : base("name=ApartmentContext") { }
public DbSet<Apartment> Apartments { get; set; }
}
CONTROLLER
public ActionResult Index()
{
ApartmentContext db = new ApartmentContext();
var apartments = db.Apartments.Where(a => a.no_of_rooms == 5);
return View(apartments);
}
Is this the correct way to apply "where clause" to a select statement? I dont want to select all the data and then eliminate the unwanted rows. This seems weird to me but everybody suggest this, at least the tutorials I read suggest this.
Well which ever tutorial you read that from is wrong (in my opinion). You shouldn't be returning actual entities to your view, you should be returning view models. Here's how I would re-write your example:
public class ApartmentViewModel
{
public int RoomCount { get; set; }
...
}
public ActionResult Index()
{
using (var db = new ApartmentContext())
{
var apartments = from a in db.Apartments
where a.no_of_rooms == 5
select new ApartmentViewModel()
{
RoomCount = a.no_of_rooms
...
};
return View(apartments.ToList());
}
}
Is this the correct way to apply "where clause" to a select statement?
Yes, this way is fine. However, you need to understand what's actually happening when you call Where (and various other LINQ commands) on IQueryable<T>. I assume you are using EF and as such the Where query would not execute immediately (as EF uses delayed execution). So basically you are passing your view a query which has yet to be run and only at the point of where the view attempts to render the data is when the query will run - by which time your ApartmentContext will have been disposed and as a result throw an exception.
db.Apartments.Where(...).ToList();
This causes the query to execute immediately and means your query no longer relys on the context. However, it's still not the correct thing to do in MVC, the example I have provided is considered the recommended approach.
In our project, we will add a Data Access Layer instead of accessing Domain in controller. And return view model instead of Domain.
But your code, you only select the data you need not all the data.
If you open SQL Profiler you'll see that's a select statement with a where condition.
So if it's not a big project I think it's OK.
I can't see these tutorials but are you sure it's loading all the data? It looks like your using entity framework and entity framework uses Lazy laoding. And Lazy loading states:
With lazy loading enabled, related objects are loaded when they are
accessed through a navigation property.
So it might appear that your loading all the data but the data itself is only retrieved from SQL when you access the object itself.
I have a little project where I'm running MVC3.
I use LINQ to fetch data from the database.
I built my project with the same architectural design as the premade examples that come with MVC3.
In such a project, the application is split up and in this topic I want to focus on the Model.cs files. I have one for each controller at the moment, So as an example, I have a HighscoreController.cs and a HighscoreModels.cs. In the model class I define a Service class that has a reference to a datacontext and some methods that use this datacontext to query the database.
Now i ran into the problem that some of these methods are executing the same queries, and therefore I wanted to make a central point of access to the database so I thought I would implement the Repository Pattern, and so I did.
So instead of having a reference to a datacontext in the Service class I now have a reference to the repository as such:
private IRepository _repository;
public HighscoreService()
: this(new Repository())
{ }
public HighscoreService(IRepository repository)
{
_repository = repository;
}
Now the database calls are handled within the repository and the repository is used from the Service class through the _repository reference.
My repository is built like this:
public class Repository : IRepository
{
private MyDataContext _dataContext;
public Repository()
{
_dataContext = new MyDataContext();
}
public Member MemberByName(string memberName)
{
Member member = CompiledQueries.MemberByName(_dataContext, memberName);
return member;
}
}
The problem I face appears when I try to use DataLoadOptions in combination with this repository pattern.
Because when you use dataloadoptions, you must not have made previous queries on the datacontext before a new dataloadoptions is applied to it. And since my repository reuses the datacontext throughout all methods, this does not work out at all.
I have been trying 2 things, one is recreating the datacontext within every methods, by way of the using statement, to make sure that the datacontext is refreshed every time. But then I get problems when I have fetched the result from the repository back into my model and the scope runs out inside the repository pattern, as the using statement ends, which means that the result cannot be used with e.g. .Count() or .ToList() because the datacontext that supplied me the data has been terminated. I also tried another solution where it uses the same datacontext throughout the whole repository, but makes a new instance in each method that uses dataloadoptions. This felt very dirty ;)
So can anyone give me a suggestion on how to use DataLoadOptions with the repository pattern? and avoid the problems I just described. Or should i not use dataloadoptions and choose another way of doing it? The reason i use DataLoadOptions by the way, is that I want to have some data from related tables.
As a little question on the side: In the code example above you can see that I have placed CompiledQueries within a .cs file of its own. Is this a bad design? Are there any guidelines for where to put compiled queries in an MVC application?
Thanks for reading and hope there are some answers for my questions ;) thanks a lot in advance. If you need more information, just ask.
I am by no means an expert on DataLoadOptions, but from your question and what I've read about it, it seems that you need to use it for eager loading. In reference to this:
"Because when you use dataloadoptions, you must not have made previous queries on the datacontext before a new dataloadoptions is applied to it."
.. to me this sounds like a shortcoming or design flaw with DataLoadOptions (I personally use Entity Framework, not LINQ to SQL). While I do think it's a good idea to have a single data context per HTTP request as offered in the first 2 comments by ngm and CrazyCoderz, I don't think this will solve your problem. If you want to reuse a single data context within a single HTTP request, as soon as you execute the first query, it sounds like you will be unable to set the DataLoadOptions on the data context to a new value.
I saw a presentation at vslive vegas where the presenter offered one of the solutions you mentioned, creating a new data context in each repository method. What you would have to do here is call ToList() or ToArray() before terminating the using statement and returning the method result(s).
As you mentioned, this would make objects not pre-loaded into the enumeration inaccessible after the method returns. However, if you already have the query executed and converted to a List, Collection, Array, or some other concrete IEnumerable, you don't need access to the Count() or ToList() methods any longer. Instead, you can use Array.Length or List.Count or Collection.Count properties.
What else is stopping you from creating a new data context in each repository method? Meaning, what do you need the data context for, after executing the repository method, that you can't get because it's been disposed of?
Reply to comments
For your first query, can you do this?
public Member GetSomeRandomMember()
{
Member[] members = null;
using (var context = new MyDataContext())
{
// execute the query to get the whole table
members = context.Members.ToArray();
}
// do not need to query again
var totalRows = members.Length;
var skipThisMany = PerformRandomNumberComputation(totalRows);
return members.Skip(skipThisMany).FirstOrDefault();
}
Granted that might not be optimal if your Members table has a lot of rows. In that case you would want to execute 2 queries -- 1 to count, and a second to select the row. You could achieve that by opening 2 contexts:
public Member GetSomeRandomMember()
{
using (var context1 = new MyDataContext())
var totalRows = context1.Members.Count();
var skipThisMany = PerformRandomNumberComputation(totalRows);
Member member = null;
using (var context2 = new MyDataContext())
member = context2.Members.Skip(skipThisMany).FirstOrDefault();
return member;
}
For the second part of your comment, I'm not sure I get what you are talking about. The fetching of the data and the making changes to it should all come in a single operation with a single context anyways:
public void SaveMember(int id, string email, bool isSuspended)
{
using (var context = new MyDataContext())
{
var member = context.Members.Single(m => m.Id == id);
member.Email = email;
member.IsSuspended = isSuspended;
context.SaveChanges(); // or whatever the linq to sql equivalent is
}
}
If you want to pass the whole entity to the repository method, you should still query it out so that it is attached to the correct context:
public void SaveMember(Member member)
{
var memberDto = member;
using (var context = new MyDataContext())
{
member = context.Members.Single(m => m.Id == memberDto.Id);
member.Email = memberDto.Email;
member.IsSuspended = memberDto.IsSuspended;
context.SaveChanges(); // or whatever the linq to sql equivalent is
}
}
I was reading Steven Sanderson's book Pro ASP.NET MVC Framework and he suggests using a repository pattern:
public interface IProductsRepository
{
IQueryable<Product> Products { get; }
void SaveProduct(Product product);
}
He accesses the products repository directly from his Controllers, but since I will have both a web page and web service, I wanted to have add a "Service Layer" that would be called by the Controllers and the web services:
public class ProductService
{
private IProductsRepository productsRepsitory;
public ProductService(IProductsRepository productsRepository)
{
this.productsRepsitory = productsRepository;
}
public Product GetProductById(int id)
{
return (from p in productsRepsitory.Products
where p.ProductID == id
select p).First();
}
// more methods
}
This seems all fine, but my problem is that I can't use his SaveProduct(Product product) because:
1) I want to only allow certain fields to be changed in the Product table
2) I want to keep an audit log of each change made to each field of the Product table, so I would have to have methods for each field that I allow to be updated.
My initial plan was to have a method in ProductService like this:
public void ChangeProductName(Product product, string newProductName);
Which then calls IProductsRepository.SaveProduct(Product)
But there are a few problems I see with this:
1) Isn't it not very "OO" to pass in the Product object like this? However, I can't see how this code could go in the Product class since it should just be a dumb data object. I could see adding validation to a partial class, but not this.
2) How do I ensure that no one changed any other fields other than Product before I persist the change?
I'm basically torn because I can't put the auditing/update code in Product and the ProductService class' update methods just seem unnatural (However, GetProductById seems perfectly natural to me).
I think I'd still have these problems even if I didn't have the auditing requirement. Either way I want to limit what fields can be changed in one class rather than duplicating the logic in both the web site and the web services.
Is my design pattern just bad in the first place or can I somehow make this work in a clean way?
Any insight would be greatly appreciated.
I split the repository into two interfaces, one for reading and one for writing.
The reading implements IDisposeable, and reuses the same data-context for its lifetime. It returns the entity objects produced by linq to SQL. For example, it might look like:
interface Reader : IDisposeable
{
IQueryable<Product> Products;
IQueryable<Order> Orders;
IQueryable<Customer> Customers;
}
The iQueryable is important so I get the delayed evaluation goodness of linq2sql. This is easy to implement with a DataContext, and easy enough to fake. Note that when I use this interface I never use the autogenerated fields for related rows (ie, no fair using order.Products directly, calls must join on the appropriate ID columns). This is a limitation I don't mind living with considering how much easier it makes faking read repository for unit tests.
The writing one uses a separate datacontext per write operation, so it does not implement IDisposeable. It does NOT take entity objects as input or out- it takes the specific fields needed for each write operation.
When I write test code, I can substitute the readable interface with a fake implementation that uses a bunch of List<>s which I populate manually. I use mocks for the write interface. This has worked like a charm so far.
Don't get in a habit of passing the entity objects around, they're bound to the datacontext's lifetime and it leads to unfortunate coupling between your repository and its clients.
To address your need for the auditing/logging of changes, just today I put the finishing touches on a system I'll suggest for your consideration. The idea is to serialize (easily done if you are using LTS entity objects and through the magic of the DataContractSerializer) the "before" and "after" state of your object, then save these to a logging table.
My logging table has columns for the date, username, a foreign key to the affected entity, and title/quick summary of the action, such as "Product was updated". There is also a single column for storing the change itself, which is a general-purpose field for storing a mini-XML representation of the "before and after" state. For example, here's what I'm logging:
<ProductUpdated>
<Deleted><Product ... /></Deleted>
<Inserted><Product ... /></Inserted>
</ProductUpdated>
Here is the general purpose "serializer" I used:
public string SerializeObject(object obj)
{
// See http://msdn.microsoft.com/en-us/library/bb546184.aspx :
Type t = obj.GetType();
DataContractSerializer dcs = new DataContractSerializer(t);
StringBuilder sb = new StringBuilder();
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
XmlWriter writer = XmlWriter.Create(sb, settings);
dcs.WriteObject(writer, obj);
writer.Close();
string xml = sb.ToString();
return xml;
}
Then, when updating (can also be used for logging inserts/deletes), grab the state before you do your model-binding, then again afterwards. Shove into an XML wrapper and log it! (or I suppose you could use two columns in your logging table for these, although my XML approach allows me to attach any other information that might be helpful).
Furthermore, if you want to only allow certain fields to be updated, you'll be able to do this with either a "whitelist/blacklist" in your controller's action method, or you could create a "ViewModel" to hand in to your controller, which could have the restrictions placed upon it that you desire. You could also look into the many partial methods and hooks that your LTS entity classes should have on them, which would allow you to detect changes to fields that you don't want.
Good luck! -Mike
Update:
For kicks, here is how I deserialize an entity (as I mentioned in my comment), for viewing its state at some later point in history: (After I've extracted it from the log entry's wrapper)
public Account DeserializeAccount(string xmlString)
{
MemoryStream s = new MemoryStream(Encoding.Unicode.GetBytes(xmlString));
DataContractSerializer dcs = new DataContractSerializer(typeof(Product));
Product product = (Product)dcs.ReadObject(s);
return product;
}
I would also recommend reading Chapter 13, "LINQ in every layer" in the book "LINQ in Action". It pretty much addresses exactly what I've been struggling with -- how to work LINQ into a 3-tier design. I'm leaning towards not using LINQ at all now after reading that chapter.