Code First Mapping to Database Views - asp.net

I have been asked to map the ASP.NET Identity classes to existing database Views for read operations, using Stored Procedures for CRUD. There are a number of StackOverflow Questions stating that is possible to map to views, also this question, this one and lastly this one.
I have mapped the classes to the Views as follows-
var applicationUser = modelBuilder.Entity<applicationUser>().HasKey(au => au.Id) //Specify our own View and Stored Procedure names instead of the default tables
.ToTable("User", "Users").MapToStoredProcedures(sp =>
{
sp.Delete(d => d.HasName("spUser_Delete", "Users"));
sp.Insert(i => i.HasName("spUser_Create", "Users"));
sp.Delete(u => u.HasName("spUser_Update", "Users"));
});
Where [Users].[User] is a SQL view retrieving data from the SQL table [Users].[tblUser].
Unfortunately I have had to leave at least one of the classes mapped to a table rather than View as Entity Framework generates the following SQL-
SELECT Count(*)
FROM INFORMATION_SCHEMA.TABLES AS t
WHERE t.TABLE_TYPE = 'BASE TABLE'
AND (t.TABLE_SCHEMA + '.' + t.TABLE_NAME IN ('Users.ApplicationRole','Users.User','Users.AuthenticationToken','Users.UserClaim','Users.UserLogin','Users.UserRole','Users.Department','Users.PasswordResetToken','Users.UserDepartment')
OR t.TABLE_NAME = 'EdmMetadata')
go
Which returns zero as these are Views and not tables.
As a result any attempt to use the UserManager results in the exception-
Value cannot be null. Parameter name: source
Description: An unhandled exception occurred during the execution of
the current web request. Please review the stack trace for more
information about the error and where it originated in the code.
Exception Details: System.ArgumentNullException: Value cannot be null.
Parameter name: source
Source Error:
Line 48: if (ModelState.IsValid)
Line 49: {
Line 50: var userAccount = await
UserManager.FindByNameAsync(model.UserName);
Line 51:
Line 52: if (userAccount == null)
Manually changing the query to-
SELECT Count(*)
FROM INFORMATION_SCHEMA.TABLES AS t
WHERE (t.TABLE_SCHEMA + '.' + t.TABLE_NAME IN ('Users.ApplicationRole','Users.User','Users.AuthenticationToken','Users.UserClaim','Users.UserLogin','Users.UserRole','Users.Department','Users.PasswordResetToken','Users.UserDepartment')
OR t.TABLE_NAME = 'EdmMetadata')
go
Returns the correct nine Views and would presumably not cause the error. Simply having one of the classes mapped to a table is sufficient to convince it the database is correct and to carry on as normal.
Is there any way I can persuade Entity Framework to remove the "Is a table" requirement, or assert that the tables do exist and therefore skip this step altogether?
Edit: Following a request, the code for the UserManager is included below-
AccountController.cs
[Authorize]
public class AccountController : Controller
{
public AccountController()
: this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationIdentityDbContext())))
{
}
public AccountController(UserManager<ApplicationUser> userManager)
{
UserManager = userManager;
}
public UserManager<ApplicationUser> UserManager { get; private set; }

I have managed to resolve this problem by creating a custom Database Initializer which replaces the default CreateDatabaseIfNotExists initializer. The Codeguru article on Understanding Database Initializers in Entity Framework Code First was enormously helpful in helping me understand what was going on.
Code for solution-
using System.Data.Entity;
namespace NexGen.Data.Identity
{
public class IdentityCustomInitializer : IDatabaseInitializer<ApplicationIdentityDbContext>
{
public void InitializeDatabase(ApplicationIdentityDbContext)
{
return; //Do nothing, database will already have been created using scripts
}
}
}
IdentityManager-
public class ApplicationIdentityDbContext: IdentityDbContext<ApplicationUser>
{
public ApplicationIdentityDbContext() : base("DefaultConnection")
{
Database.SetInitializer(new IdentityCustomInitializer());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
...
As a result of this code there are no longer any probing queries by Entity Framework attempting to check if the database exists (and failing due to the assumption that tables, rather than views, were mapped) - instead the queries are immediately against the view attempting to retrieve the user data (and then executing a Stored Procedure in the case the initial action was a registration or otherwise updating the user).

please try
[Authorize]
public class AccountController : Controller
{
public AccountController()
{
InitAccountController(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationIdentityDbContext())))
}
private InitAccountController(UserManager<ApplicationUser> userManager)
{
UserManager = userManager;
}
public UserManager<ApplicationUser> UserManager { get; private set; }
}

some more explanations:
in EF6 code we can see the following function (DatabaseTableChecker.cs):
public bool AnyModelTableExistsInDatabase(
ObjectContext context, DbConnection connection, List<EntitySet> modelTables, string edmMetadataContextTableName)
{
var modelTablesListBuilder = new StringBuilder();
foreach (var modelTable in modelTables)
{
modelTablesListBuilder.Append("'");
modelTablesListBuilder.Append((string)modelTable.MetadataProperties["Schema"].Value);
modelTablesListBuilder.Append(".");
modelTablesListBuilder.Append(GetTableName(modelTable));
modelTablesListBuilder.Append("',");
}
modelTablesListBuilder.Remove(modelTablesListBuilder.Length - 1, 1);
using (var command = new InterceptableDbCommand(
connection.CreateCommand(), context.InterceptionContext))
{
command.CommandText = #"
SELECT Count(*)
FROM INFORMATION_SCHEMA.TABLES AS t
WHERE t.TABLE_TYPE = 'BASE TABLE'
AND (t.TABLE_SCHEMA + '.' + t.TABLE_NAME IN (" + modelTablesListBuilder + #")
OR t.TABLE_NAME = '" + edmMetadataContextTableName + "')";
var executionStrategy = DbProviderServices.GetExecutionStrategy(connection);
try
{
return executionStrategy.Execute(
() =>
{
if (connection.State == ConnectionState.Broken)
{
connection.Close();
}
if (connection.State == ConnectionState.Closed)
{
connection.Open();
}
return (int)command.ExecuteScalar() > 0;
});
}
finally
{
if (connection.State != ConnectionState.Closed)
{
connection.Close();
}
}
}
}
which corresponds to what you discover.
From this function we may says that there is a problem if, and only if, there are/is only views mapped to the model. In this case the initializer considers the database as Existing but Empty, and he tries to create the tables.
This creates problems as there are/is still views in the database with the same name as the tables the initializer wants to create.
So a work around seems to have at least one real table mapped to the context. No need for a custom initializer in this case.
I propose it as an issue : model only mapped to views

From my understanding and tests there is no need to implement an IDatabaseInitializer having an empty InitializeDatabase method like pwdst did.
From what I saw at Understanding Database Initializers in Entity Framework Code First, it is sufficient to call
Database.SetInitializer<ApplicationIdentityDbContext>(null);
when the application is initializing, or better say, before the first time the database will be accessed.
I would not put it inside the ctor of my DbContext class to avoid setting the initializer every time a DbContext instance is created. Instead, I would put it into the application's initialization method or as one of the first statements of the Main() method.
This worked fine for my application using Entity Framework 6.

Related

How to design repository based on Entity Framework core?

I have created a Repository on top of Entity Framework Core, but have some issues with how it's done.
This is an example:
public class StockPricesRepository : IStockPricesRepository
{
StockPricesDbContext _stockPricesDbContext;
ILogger _logger;
public StockPricesRepository(StockPricesDbContext stockPricesDbContext, ILogger logger)
{
_stockPricesDbContext = stockPricesDbContext;
_logger = logger;
}
public void Add(StockPrice stockPrice)
{
_stockPricesDbContext.Add(stockPrice);
_stockPricesDbContext.SaveChanges();
}
public void AddOrUpdate(StockPrice stockPrice)
{
if (!Exists(stockPrice))
_stockPricesDbContext.Add(stockPrice);
else
_stockPricesDbContext.Update(stockPrice);
_stockPricesDbContext.SaveChanges();
}
private bool Exists(StockPrice stockPrice)
{
StockPrice existingStockPrice = Get(stockPrice.Ticker, stockPrice.Exchange, stockPrice.Date, stockPrice.DataProvider);
return (existingStockPrice != null);
}
public StockPrice Get(string ticker, string exchange, DateTime date, string providerName)
{
StockPrice stockPrice = null;
stockPrice =
(from sp in _stockPricesDbContext.StockPrices
where (
(sp.Ticker == ticker) &
(sp.Exchange == exchange) &
(sp.Date == date) &
(sp.DataProvider == providerName))
select sp).AsNoTracking().FirstOrDefault();
return stockPrice;
}
}
}
The StockPricesDbContext is injected into the constructur using dependency injection like this:
services.AddDbContext<StockPricesDbContext>(options => options.UseSqlServer(connectionString));
The problem with the current design is that I get some issues with multiple calls into the repository within the lifetime of the StockPricesDbContext object (even if I have AsNoTracking() on the Get method):
System.InvalidOperationException: 'The instance of entity type 'StockPrice' cannot be tracked because another instance with the same key value for {'Date', 'Ticker', 'Exchange', 'DataProvider'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.'
To avoid this problem I would maybe prefer to have each of the repository methods embedded in a using block like this:
using (var db = new StockPricesDbContext())
{
}
The problem with this approach is that I don't get the StockPricesDbContext from dependency injection and the connection string from AddDbContext is lost.
One workaround for that might be to get the connection string from the constructor of the repository like this:
private string _connectionString;
public StockPricesRepository(StockPricesDbContext stockPricesDbContext, ILogger logger)
{
_stockPricesDbContext = stockPricesDbContext;
_connectionString = stockPricesDbContext.Database.GetDbConnection().ConnectionString;
_logger = logger;
}
I would also need to add this constructor in StockPricesDbContext:
public StockPricesDbContext(string connectionString)
{
_connectionString = connectionString;
}
and this would be the OnConfiguring method:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
if (_connectionString != null)
optionsBuilder.UseSqlServer(_connectionString);
}
}
Then I could use it in the methods like this:
using (var db = new StockPricesDbContext(_connectionString))
{
}
It kind of works, but seems a bit "unclean".
Has anyone else come across a good pattern for repositories built on top of Entity Framework Core?
The common mistake that causes this error is having several async queries that have not been committed.
There is no problem saving multiple records in EF though.
There are multiple approaches to avoid your issue.
Using AddRange(),UpdateRange(),DeleteRange()
AddRange() can add list of objects to your db and you don't need to call .Add() more than once. Similarly you can update or delete a list of objects
EFCore.BulkExtensions
Bulk Extensions in EFCore
Both are extending DbContext with Bulk operations and have the same syntax call:
context.BulkInsert(stockPriceList);
context.BulkUpdate(stockPriceList);
context.BulkDelete(stockPriceList);
context.BulkInsertOrUpdate(stockPriceList);

Unit Test UserManager<IdentityUser> in asp.net core

My application is an ASP.NET Core 1.0 Web API. I would like to test the following method (snipped):
public async Task<bool> GetClientsAsync()
{
foreach (var user in await this.clientAdapter.Users().ToListAsync())
{
return true;
}
return false;
}
Normally the clientAdapter is calling UserManager<IdentityUser>'s property Users. So the code for the "real" clientAdapterlooks like that:
public IQueryable<IdentityUser> Users()
{
return this.userManager.Users;
}
Now when I am testing the clientAdapter looks like the following:
private readonly List<IdentityUser> clientList;
public TestClientAdapter(){
this.clientList= this.CreateClientList();
}
public IQueryable<IdentityUser> Users()
{
return this.userList.AsQueryable();
}
The return type of the method Users() has to be IQueryable<IdentityUser> since thats the return value of the original class UserManager<IdentityUser>. Now if I execute the test I am getting the following error, as soon as it hit's the foreach loop (the problem is the ToListAsync() call):
System.NotSupportedException: "Store does not implement IQueryableUserStore<TUser>."
If I change the loop from
foreach (var user in await this.clientAdapter.Users().ToListAsync())
{
return true;
}
to
foreach (var user in this.clientAdapter.Users().ToList())
{
return true;
}
Everything works fine.
My Problem:
I am not not able to mock the UserManager since the UserManager needs a UserStore which needs a DBContext which I dont know how to mock. And even if it was possbile to mock the DBContext, I think this would turn my unit test into an integration test and I dont want that. Plus it's probably not worth the effort. So I cannot just work with a mocked Usermanager and get the data from it.
My Question:
Is it possible to make the unit test pass, without changing the method I want to test?
EDIT
#CodeCaster:
The injected clientAdapter now looks like the following (snipped):
public class TestClientAdapter: IClientAdapter, IQueryableUserStore<IdentityUser>
{
private readonly List<IdentityUser> clientList
private UserManager<IdentityUser> testUserManager;
public TestClientAdapter: ()
{
clientList= this.CreateclientList();
this.testUserManager = new UserManager<IdentityUser>(this, null, null, null, null, null, null, null, null);
}
public IQueryable<IdentityUser> Users()
{
return this.testUserManager.Users;
}
IQueryable<IdentityUser> IQueryableUserStore<IdentityUser>.Users
{
get
{
return this.clientList.AsQueryable();
}
}
Now Iam getting another Exception:
"System.InvalidOperationException" in System.Private.CoreLib.ni.dll"
ToListAsync (among of other async methods like AnyAsync, etc.) is not a standard Linq2SQL (aka IQueryable<T>) extension method from System.Linq.*.
It's part of EntityFramework and as such it assumes certain preconditions, hence it can't work with a queryable List. Basically it's a wrapper around query.AsAsyncEnumerable() and AsAsyncEnumerable checks for the existence of IAsyncEnumerable<TSource> and/or IAsyncEnumerableAccessor<TSource> and if not there throws the invalid operation exception.
There are two things you can do...
Use EF Core InMemoryDatabase for an integration test, which was made for integration tests
Refactor your code so IQueryable<T> doesn't leak outside of your repository or command/query handlers
Technically it may be possible to create an list which implements AsAsyncEnumerable<T> but I haven't tried it and most likely not working with list.AsQueryable() since it wraps the list somewhere below...
Let the clientAdapter you inject for tests also implement IQueryableUserStore<TUser>, as the UserManager casts it to that, and if that fails, throws the mentioned exception.

Testing a class library that is using different databases based on Session

I have an ASP.NET website project that until recent had all code in App_Code folder. It uses Entity Framework 4 as ORM. Application is divided into three "sections" (let's say one for each customer). Each section has it's own database (but same schema). This is due to performance reasons, databases are over 10GB each with millions of rows.
Each time a context object is created a Session variable which holds section ID is called and proprietary connection string is chosen for this context.
It looks like this (following are members of static Connection class):
public static MyEntities GetEntityContext()
{
if (HttpContext.Current.Session["section"] == null)
{
HttpContext.Current.Response.Redirect("~/Login.aspx");
}
var context = new MyEntities(GetEntityConnectionStringForSection((int)HttpContext.Current.Session["section"]);
return context;
}
private static string GetEntityConnectionStringForSection(int section)
{
switch (section)
{
case 1: return ConfigurationManager.ConnectionStrings["entity_1"].ConnectionString;
case 2: return ConfigurationManager.ConnectionStrings["entity_2"].ConnectionString;
case 3: return ConfigurationManager.ConnectionStrings["entity_3"].ConnectionString;
default: return ConfigurationManager.ConnectionStrings["entity_1"].ConnectionString;
}
}
It works very good and also handles situation when session timed out everytime any data access is performed.
Recently as I needed to share DB classes among two websites I moved all DB classes to separate class library and referenced System.Web library which I know is bad practice, but it's working.
Now the next step is to include unit and module tests which as I read is very difficult or impossible when using HttpContext in library, so I want to get rid of System.Web references. What is the best practice for this situation?
I think I can't just pass HttpContext to GetEntityContext() as it is also called from within my entity classes. Although this probably can be refactored. So maybe this is where I should go?
I also wondered if is it possible to somehow pass current section ID to this whole library? It cannot be just static property because as far as I understand it would be common for all users using the application. This should be user-specific.
Reassuming the objective is to make automated testing possible without loosing transparent Connection String choosing and session timeouts handling.
If I do something fundamentally wrong at this stage please also let me know. I can look again at this question tomorrow morning (8.00 am UTC) so please don't be discouraged by my silence till then.
EDIT:
Example of usage of Connection class in the library:
public partial class Store
{
public static List<Store> GetSpecialStores()
{
using (var context = Connection.GetEntityContext())
{
return context.Stores.Where(qq => qq.Type > 0).OrderBy(qq => qq.Code).ToList();
}
}
}
You can declare interface IContextProvider inside your library ans use it to retrieve context. Something like:
public interface IContextProvider
{
MyEntities GetEntityContext();
}
This will make your library testable. In your web project you can inject IContextProvider implementation into your library.
public class WebContextProvider : IContextProvider
{
public MyEntities GetEntityContext()
{
if (HttpContext.Current.Session["section"] == null)
HttpContext.Current.Response.Redirect("~/Login.aspx");
int sectionId = (int)HttpContext.Current.Session["section"];
string connectionString = GetEntityConnectionStringForSection(sectionId);
var context = new MyEntities(connectionString);
return context;
}
private static string GetEntityConnectionStringForSection(int section)
{
switch (section)
{
case 1: return ConfigurationManager.ConnectionStrings["entity_1"].ConnectionString;
case 2: return ConfigurationManager.ConnectionStrings["entity_2"].ConnectionString;
case 3: return ConfigurationManager.ConnectionStrings["entity_3"].ConnectionString;
default: return ConfigurationManager.ConnectionStrings["entity_1"].ConnectionString;
}
}
}
Inject this interface to repositories or other data access classes.
public partial class Store
{
private IContextProvider contextProvider;
public Store(IContextProvider contextProvider)
{
this.contextProvider = contextProvider;
}
public List<Store> GetSpecialStores()
{
using (var context = contextProvider.GetEntityContext())
{
return context.Stores.Where(qq => qq.Type > 0).OrderBy(qq => qq.Code).ToList();
}
}
}

Entity Framework telling me an object is attached when it isn't - why?

I have an object I want to update in the database. I'm new to EF but have done a fair bit of reading. Clearly my approach is wrong, but I don't understand why. FYI the Context referenced throughout is an ObjectContext which is newly instantiated as this code begins and is disposed immediately after. Here is my Update method - the View is the object I want to update in the database and it has 4 ICollection properties whose changes I also wish to save to the database:
public void Update(View view)
{
var original = Read(view.Username, view.ViewId);
original.ViewName = view.ViewName;
ProcessChanges<CostCentre, short>(Context.CostCentres, original.CostCentres, view.CostCentres, "iFinanceEntities.CostCentres", "CostCentreId");
ProcessChanges<LedgerGroup, byte>(Context.LedgerGroups, original.LedgerGroups, view.LedgerGroups, "iFinanceEntities.LedgerGroups", "LedgerGroupId");
ProcessChanges<Division, byte>(Context.Divisions, original.Divisions, view.Divisions, "iFinanceEntities.Divisions", "DivisionId");
ProcessChanges<AnalysisCode, short>(Context.AnalysisCodes, original.AnalysisCodes, view.AnalysisCodes, "iFinanceEntities.AnalysisCodes", "AnalysisCodeId");
int test = Context.SaveChanges();
}
First I get the original from the database because I want to compare its collections with the new set of collections. This should ensure the correct sub-objects are added and removed. I compare each collection in turn using this ProcessChanges method:
private void ProcessChanges<TEntity, TKey>(ObjectSet<TEntity> contextObjects, ICollection<TEntity> originalCollection, ICollection<TEntity> changedCollection, string entitySetName, string pkColumnName)
where TEntity : class, ILookupEntity<TKey>
{
List<TKey> toAdd = changedCollection
.Select(c => c.LookupKey)
.Except(originalCollection.Select(o => o.LookupKey))
.ToList();
List<TKey> toRemove = originalCollection
.Select(o => o.LookupKey)
.Except(changedCollection.Select(c => c.LookupKey))
.ToList();
toAdd.ForEach(a =>
{
var o = changedCollection.Single(c => c.LookupKey.Equals(a));
AttachToOrGet<TEntity, TKey>(entitySetName, pkColumnName, ref o);
originalCollection.Add(o);
});
toRemove.ForEach(r =>
{
var o = originalCollection.Single(c => c.LookupKey.Equals(r));
originalCollection.Remove(o);
});
}
This compares the new collection to the old one and works out which objects to add and which to remove. Note that the collections all contain objects which implement ILookupEntity.
My problems occur on the line where I call AttachToOrGet. This method I got from elsewhere on stackoverflow. I'm using this because I was often getting a message saying that "An object with the same key already exists in the ObjectStateManager" when attaching a new subobject. Hopefully you'll understand my confusion around this when I post the code of this method below:
public void AttachToOrGet<TEntity, TKey>(string entitySetName, string pkColumnName, ref TEntity entity)
where TEntity : class, ILookupEntity<TKey>
{
ObjectStateEntry entry;
// Track whether we need to perform an attach
bool attach = false;
if (Context.ObjectStateManager.TryGetObjectStateEntry(new EntityKey(entitySetName, pkColumnName, entity.LookupKey), out entry))
//if (Context.ObjectStateManager.TryGetObjectStateEntry(Context.CreateEntityKey(entitySetName, entity), out entry))
{
// Re-attach if necessary
attach = entry.State == EntityState.Detached;
// Get the discovered entity to the ref
entity = (TEntity)entry.Entity;
}
else
{
// Attach for the first time
attach = true;
}
if (attach)
Context.AttachTo(entitySetName, entity);
}
Basically this is saying if the entity is not already attached then attach it. But my code is returning false on the Context.ObjectStateManager.TryGetObjectStateEntry line, but throwing an exception on the final line with the message "An object with the same key already exists in the ObjectStateManager". To me this is paradoxical.
As far as I'm concerned I'm trying to achieve something very simple. Something it would take 20 minutes to write a stored procedure for. A simple database update. Frankly I don't care what is attached and what isn't because I don't wish to track changes or create proxies or lazy load or do anything else EF offers me. I just want to take a very simple object and update the database using a minimal number of trips between servers. How is this so complicated? Please someone help me - I've spent a whole day on this!
Update
Here's my ILookupEntity class:
public interface ILookupEntity<TKey>
{
TKey LookupKey { get; }
string DisplayText { get; }
}
Here's how it is implemented in CostCentre:
public partial class CostCentre : IFinancialCode, ILookupEntity<short>
{
#region IFinancialCode Members
public short ID { get { return CostCentreId; } }
public string DisplayText { get { return string.Format("{0} - {1}", Code, Description); } }
#endregion
#region ILookupEntity Members
public short LookupKey
{
get { return ID; }
}
#endregion ILookupEntity Members
}
Well, I've worked through this and found a solution, but I can't say I understand it. The crucial ingredient came when I was performing a check after the comment by #Slauma. I wanted to check I was using the correct entity set name etc so I included the following lines near the top of my AttachToOrGet method:
var key = new EntityKey(entitySetName, pkColumnName, entity.LookupKey);
object temp;
if (!Context.TryGetObjectByKey(key, out temp))
throw new Exception(string.Format("No entity was found in {0} with key {1}", entitySetName, entity.LookupKey));
Bizarrely this alone resolved the problem. For some reason, once I'd called the TryGetObjectByKey then the ObjectStateManager.TryGetObjectStateEntry call actually started locating the attached entity. Miraculous. I'd love it if anyone can explain this.
By the way, I also needed to include the following code, but that's just because in my case the modelled entities are located in a separate assembly from the context itself.
Assembly assembly = typeof(CostCentre).Assembly;
Context.MetadataWorkspace.LoadFromAssembly(assembly);

LINQ :: Use static DataContext to prevent Concurrency Problem

i am facing some problems in my project. when i try to update entity it gives me different type of errors.
i read from net. these errors are because
1 - I am getting Object of entity class from method which creates DataContext locally
and in update method id does not update because here another DataContext is created locally.
(even it does not throw any exception)
i found many articles related to this problem
1 - Adding timestamp column in table (does not effect in my project. i tried this)
one guy said that use SINGLE DataContext for everyone.
i did this by creating the following class
public class Factory
{
private static LinqDemoDbDataContext db = null;
public static LinqDemoDbDataContext DB
{
get
{
if (db == null)
db = new LinqDemoDbDataContext();
return db;
}
}
}
public static Student GetStudent(long id)
{
LinqDemoDbDataContext db = Factory.DB;
//LinqDemoDbDataContext db = new LinqDemoDbDataContext();
Student std = (from s in db.Students
where s.ID == id
select s).Single();
return std;
}
public static void UpdateStudent(long studentId, string name, string address)
{
Student std = GetStudent(studentId);
LinqDemoDbDataContext db = Factory.DB;
std.Name = name;
std.Address = address;
db.SubmitChanges();
}
in this case i want to update student details.
it solved my problem. but now the question is.
Is it good approach to use above technique in Web Based application???
Is it good approach to use above technique in Web Based application???
No. DataContext is not thread safe. You cannot share 1 DataContext among the different threads handling different requests safely.
Also - this pattern is called Singleton, not Factory

Resources