What is the custom wen the record inserting/updating is carried out?
I have this Log table in the MS SQL server database, and a C# class (example is simplified)
[Table(Name = "dbo.Sys_Log")]
public class Sys_Log
{
// Read-only, db-generated primary key ID
private int _logID;
[Column(IsPrimaryKey=true, Storage="_logID", IsDbGenerated=true)]
public int logID
{
get
{
return this._logID;
}
}
// Read-only db-generated datetime field
private System.DateTime _logTime;
[Column(Storage="_logTime", IsDbGenerated=true)]
public System.DateTime logTime
{
get
{
return this._logTime;
}
}
// Read-write string field
private string _logEvent;
[Column(Storage="_logEvent")]
public string logEvent
{
get
{
return this._logEvent;
}
set
{
this._logEvent = value;
}
}
public Sys_Log() {}
public Sys_Log(string logEvent)
{
this.logEvent = logEvent;
}
}
And this is how I add a log entry:
Table<Sys_Log> linqLog = db.GetTable<Sys_Log>();
Sys_Log l = new Sys_Log("event");
linqLog.InsertOnSubmit(l);
db.SubmitChanges();
I am not particularly happy about this code. I'd like something like this instead:
Sys_Log.Log("event");
I have idea how this can be achieved, but I'd like to know if I am following the LINQ philosophy. With this code added to the Sys_Log class
private static DataContext db;
public static void Connect(DataContext db)
{
Sys_Log.db = db;
}
public static void Log(string logEvent)
{
Table<Sys_Log> linqLog = db.GetTable<Sys_Log>();
Sys_Log l = new Sys_Log(logEvent);
linqLog.InsertOnSubmit(l);
db.SubmitChanges();
}
I can now do this:
Sys_Log.Connect(db); // Only once, at init
Sys_Log.Log("event1");
Sys_Log.Log("event2");
Are there any pitfalls, apart from the fact that the database is updated several times, that could be considered ineffective?
************** Update ******************
Following the advice of #usr not to reuse the DataContext object, I have made these changes to the Sys_Log class:
private static SqlConnection db;
public static void Connect(SqlConnection db)
{
Sys_Log.db = db;
}
public static void Log(string logEvent)
{
DataContext ctx = new DataContext(db);
ctx.CommandTimeout = 240;
Table<Sys_Log> linqLog = ctx.GetTable<Sys_Log>();
Sys_Log l = new Sys_Log(logEvent);
linqLog.InsertOnSubmit(l);
ctx.SubmitChanges();
}
Use a fresh data context each time. Reusing the same context has to catastrophic consequences:
No entity memory is ever released
When an invalid entity enters the context (due to a bug) it is stuck and will forever prevent SubmitChanges from succeeding. The application will never recover
Also note, that L2S is deprecated and EF has superseded it.
You can share a SqlConnection and use it long-term if you really want. That requires, through, that you deal with broken connections. Thanks to connection pooling there are little performance incentives to do this.
It usually is the easiest and most clear way to use throw-away connections. Inject a factory, for example:
Func<SqlConnection> myFactory = () => new SqlConnection(myConnStr);
That's all there is to it. Use it, as always, with using:
using(var conn = myFactory()) { ... }
Related
I know this question has been asked before, but in those questions there aren't enough details about the actual implementation, so I decided to search for some information about how can this be achieve and this is what I've got so far:
The IUnitOfWork Interface:
public interface IUnitOfWork : IDisposable
{
IDomainTableRepository DomainTables { get; }
IVariableRepository Variables { get; }
IModelRepository Models { get; }
IStructureRepository Structures { get; }
ISentenceRepository Sentences { get; }
IExpressionRepository Expressions { get; }
IReturnRepository Returns { get; }
void Commit();
}
The implementation for IUnitOfWork:
public class SqlUnitOfWork : IUnitOfWork
{
const string ConnectionStringName = "DefaultConnection";
private AdoNetContext _context;
private DomainTableRepository _domainTables;
private VariableRepository _variables;
private ModelRepository _models;
private StructureRepository _structures;
private SentenceRepository _sentences;
private ExpressionRepository _expressions;
private ReturnRepository _returns;
public SqlUnitOfWork()
{
var connectionString =
ConfigurationManager
.ConnectionStrings[ConnectionStringName]
.ConnectionString;
_context = new AdoNetContext(connectionString, true);
}
public IDomainTableRepository DomainTables
{
get
{
if (_domainTables == null)
{
_domainTables = new DomainTableRepository(_context);
}
return _domainTables;
}
}
//...getters for the remaining repositories
public void Commit()
{
_context.SaveChanges();
}
#region IDisposable Support
private bool disposedValue = false;
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
_context.Dispose();
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(true);
}
#endregion
}
The AdoNetContext class
All the credit for the implementation of this class goes to #jgauffin.
His original blog post can be found here.
public class AdoNetContext : IDisposable
{
private IDbConnection _connection;
private bool _ownsConnection;
private IDbTransaction _transaction;
public AdoNetContext(string connectionString, bool ownsConnection)
{
_connection = new SqlConnection(connectionString);
_connection.Open();
_ownsConnection = ownsConnection;
_transaction = _connection.BeginTransaction();
}
public IDbCommand CreateCommand()
{
var command = _connection.CreateCommand();
command.Transaction = _transaction;
return command;
}
public void SaveChanges()
{
if (_transaction == null)
{
throw new InvalidOperationException("Transaction have already been already been commited. Check your transaction handling.");
}
_transaction.Commit();
_transaction = null;
}
public void Dispose()
{
if (_transaction != null)
{
_transaction.Rollback();
_transaction = null;
}
if (_connection != null && _ownsConnection)
{
_connection.Close();
_connection = null;
}
}
}
The implementation of a repository(DomainTableRepository) that uses AdoNetContext:
public class DomainTableRepository : IDomainTableRepository
{
private AdoNetContext _context;
public DomainTableRepository(AdoNetContext context)
{
_context = context;
}
public DomainTable Get(int id)
{
DomainTable table;
using (var commandTable = _context.CreateCommand())
{
commandTable.CommandType = CommandType.StoredProcedure;
commandTable.CommandText = "up_DomainTable_GetById";
commandTable.Parameters.Add(commandTable.CreateParameter("#pId", id));
table = ToList(commandTable).FirstOrDefault();
}
return table;
}
public IEnumerable<DomainTable> GetAll(int pageIndex = 1, int pageSize = 10)
{
using (var command = _context.CreateCommand())
{
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "up_DomainTable_GetAll";
command.Parameters.Add(command.CreateParameter("#pPageIndex", pageIndex));
command.Parameters.Add(command.CreateParameter("#pPageSize", pageSize));
return ToList(command).ToList();
}
}
public int Remove(DomainTable entity)
{
using (var command = _context.CreateCommand())
{
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "up_DomainTable_Delete";
command.Parameters.Add(command.CreateParameter("#pId", entity.Id));
return command.ExecuteNonQuery();
}
}
}
I apologize for posting so much code,but I want to make sure you understand everything about what I want to ask.
First, I created an interface for the UoW(IUnitOfWork), because in the future I might want to change to an ORM like EF, but since I'm just taking my first step into the the world of back-end programming I wanted to start with ADO.NET and stored procedures.
So here are my questions regarding the implementation of the UoW pattern with ADO.NET and its usage in ASP.NET MVC:
1)Given the code for the AdoNetContext(the one that manages the db connection and transactions), is there any performance penalty for always creating a transaction?
This is what I read in a SQL book :"Executing a SELECT
statement within a transaction can create locks on the referenced tables, which can in turn block other users or sessions from performing work or reading data" Do the transactions created in C# behave exactly as their counterparts in SQL?
2)As you can see in IUnitOfWork and its implementation (UnitOfWork), I have readonly properties for every repository I have in my application. This a common "pattern" I've seen in lots of tutorials on EF and I found it very convenient since every time I new up a instance of IUnitOfWork I already have access to all its repositories and I don't have to clutter my code with the instantiation of the repositories I need in a specific Action (from a Controller).
Do you think it would too much overhead to instantiate all the repositories (as SQLUnitOfWork does) every time I create/inject a new instance of IUnitOfWork? There are some scenarios in which I might work with 4 or 5 repositories at the same time, but in most cases I'll be using just 1 or 2 in the same action.
3) I would like to use DI (maybe Ninject) to inject an instance of IUnitOfWork into my Controllers. This way later when I use another persistence framework, I will only have to change this line kernel.Bind<IUnitOfWork>().To<SqlUnitOfWork>(); From SqlUnitOfWork, to let's say EFUnitOfWork.
The problem I've encountered here is that the Dispose methods in SqlUnitOfWork and AdoNetContext are never called and as much as I want to use DI I'd rather wrap the instantiation of SqlUnitOfWork in an using statement in every Action instead of be leaking memory just so that I can use DI.
So this is what I wanted to ask you guys.
I'm trying to learn so please before clicking the close link or marking the question as a duplicate take some time to read my question.
Thanks.
How can one set the TransactionHandler for ObjectContext?
I am checking this example: Handling of Transaction Commit Failures, but it only shows for DbContext.
TransactionHandler also works for ObjectContext. The only problem is that the code based configurations (DbConfiguration) are not evaluated before the first DbContext is instantiated.
Two possible workarounds
Dummy DbContext:
public class MyDbConfiguration : DbConfiguration
{
public MyDbConfiguration()
{
SetTransactionHandler(SqlProviderServices.ProviderInvariantName,
() => new CommitFailureHandler());
}
}
public class TestContext : DbContext { }
static void Main(string[] args)
{
// instantiate DbContext to initialize code based configuration
using (var db = new TestContext()) { }
using (var db = new TransactionHandlerDemoEntities()) {
var handler = db.TransactionHandler; // should be CommitFailureHandler
db.AddToDemoTable(new DemoTable { Name = "TestEntiry1" });
db.SaveChanges();
}
}
Or DbConfiguration.Loaded event
static void Main(string[] args)
{
DbConfiguration.Loaded += DbConfiguration_Loaded;
using (var db = new TransactionHandlerDemoEntities()) {
var handler = db.TransactionHandler;
db.AddToDemoTable(new DemoTable { Name = "TestEntiry1" });
db.SaveChanges();
}
}
static void DbConfiguration_Loaded(object sender, DbConfigurationLoadedEventArgs e)
{
e.AddDependencyResolver(new TransactionHandlerResolver(
() => new CommitFailureHandler(),
SqlProviderServices.ProviderInvariantName,
null),true);
}
TransactionHandlerDemoEntities is an ObjectContext.
This is exclusively for DbContext. If you can, refactor your ObjectContext-based application into DbContext as soon as possible. I think that many more new features will appear that only work with the DbContext API. Maybe ObjectContext will even get deprecated as a public API some day.
You can create a DbContext from an ObjectContext, but I don't think that's of much help to you. The main problem is undoubtedly that the rest of the data logic currently expects ObjectContext.
I would like to use Entity Framework Code first approach with SQLCE4 database. Everything seems to be really nice but I have problem with debugging sql queries. I found that EFTracing from http://efwrappers.codeplex.com/ should be exactly what I need but I don't know how to use it without app.config file. I am not big fan of this configuration. I want to use only C# code to set everything up and running. I think it should be fine to use code like this:
using (System.Data.Common.DbConnection c =
new EFTracingProvider.EFTracingConnection(
new System.Data.SqlServerCe.SqlCeConnection(conn)))
{
using (var context = new MyContext(c))
{
var a = from data in context.Projects select data;
}
}
But it doesn't work. It throws exception:
Unable to determine the provider name for connection of type
EFTracingProvider.EFTracingConnection'.
Is there any simple way how to correctly create wrapped connection only in code?
Solution for my problem is following DbContext object.
public class MyContext : DbContext
{
public MyContext()
: base(CreateConnection("Data Source=file.sdf",
"System.Data.SqlServerCe.4.0"), true)
{ }
public DbSet<Project> Projects { get; set; }
public static bool TraceEnabled = true;
private static DbConnection CreateConnection(string connectionString,
string providerInvariantName)
{
DbConnection connection = null;
if (TraceEnabled)
{
EFTracingProviderConfiguration.RegisterProvider();
EFTracingProviderConfiguration.LogToConsole = true;
string wrapperConnectionString = String.Format(#"wrappedProvider={0};{1}",
providerInvariantName, connectionString);
connection = new EFTracingConnection()
{
ConnectionString = wrapperConnectionString
};
}
else
{
DbProviderFactory factory = DbProviderFactories.GetFactory(providerInvariantName);
connection = factory.CreateConnection();
connection.ConnectionString = connectionString;
}
return connection;
}
}
So now I can use just context and connection is created automatically for wrapped or unwrapped SqlCe depending on TraceEnabled property.
using (var context = new MyContext())
{
var a = context.Projects.FirstOrDefault();
}
The genuine way to trace SQL queries is to call the ToString method like that :
var t = from c in _entities.CompanyDetail
select c;
string test = t.ToString();
I don't know EFTracing, but you might want to try MVCMiniProfiler. Despite the name MVCMiniProfiler also provide SQL queries profiling and work without config file.
I've done this by creating a wrapper class around the ObjectContext and using that wrapper instead of the original context. Here's an example context wrapper:
public partial class LoggedContext : MyContext
{
public LoggedContext()
: this("name=MyEntities") // Adjust this to match your entities
{
}
public LoggedContext(string connectionString)
: base(EntityConnectionWrapperUtils.CreateEntityConnectionWithWrappers(connectionString)
{
}
private EFTracingConnection TracingConnection
{
get { return this.UnwrapConnection<EFTracingConnection>(); }
}
public event EventHandler<CommandExecutionEventArgs> CommandExecuting
{
add { this.TracingConnection.CommandExecuting += value; }
remove { this.TracingConnection.CommandExecuting -= value; }
}
public event EventHandler<CommandExecutionEventArgs> CommandFinished
{
add { this.TracingConnection.CommandFinished += value; }
remove { this.TracingConnection.CommandFinished -= value; }
}
public event EventHandler<CommandExecutionEventArgs> CommandFailed
{
add { this.TracingConnection.CommandFailed += value; }
remove { this.TracingConnection.CommandFailed -= value; }
}
}
I also have a static class that defines the tracing output method and has a static method to initialize tracing. Here:
public static class EFTracingExtensions
{
private static ILogger _logger;
public static void InitSqlTracing(ILogger logger)
{
_logger = logger;
EFTracingProviderConfiguration.RegisterProvider();
if (logger.IsLoggingEnabled()) // Don't add logging hooks if logging isn't enabled
{
EFTracingProviderConfiguration.LogAction = new Action<CommandExecutionEventArgs>(AppendSqlLog);
}
}
private static void AppendSqlLog(CommandExecutionEventArgs e)
{
if (e.Status != CommandExecutionStatus.Executing) // we only care about Finished and Failed
{
StringBuilder msg = new StringBuilder(e.ToTraceString().TrimEnd());
msg.Append(Environment.NewLine);
if (e.Result is SqlDataReader)
{
int rows = ((SqlDataReader)e.Result).HasRows ? ((SqlDataReader)e.Result).RecordsAffected : 0;
msg.AppendFormat("*** {0} rows affected", rows);
}
else if (e.Result is int)
{
msg.AppendFormat("*** result: {0}", e.Result);
}
else
{
msg.AppendFormat("*** finished, result: {0}", e.Result);
}
msg.Append(Environment.NewLine);
msg.AppendFormat(" [{0}] [{1}] in {2} seconds", e.Method, e.Status, e.Duration);
_logger.Log(msg.ToString(), LoggerCategories.SQL);
}
}
}
ILogger is the logging interface I'm using. You need to substitute your own interface/methods.
The InitSqlTracing method is invoked once when my program starts up, and then the LoggedContext class is used to log all the SQL generated by Entity Framework.
Putting it all together with your sample code:
EFTracingExtensions.InitSqlTracing(logger); // only call this once
using (var context = new LoggedContext())
{
var a = from data in context.Projects select data;
}
I have a problem with some simple code, I'm refactoring some existing code from LINQ to SQL to the Entity Framework. I'm testing my saves and deletes, and the delete is really bugging me:
[TestMethod]
public void TestSaveDelete()
{
ObjectFactory.Initialize(x =>
{
x.For<IArticleCommentRepository>().Use<ArticleCommentRepository>();
});
PLArticleComment plac = new PLArticleComment();
plac.Created = DateTime.Now;
plac.Email = "myemail";
plac.Name = "myName";
plac.Text = "myText";
plac.Title = "myTitle";
IArticleCommentRepository acrep = ObjectFactory.GetInstance<IArticleCommentRepository>();
try
{
PortalLandEntities ple = new PortalLandEntities();
int count = ple.PLArticleComment.Count();
acrep.Save(plac);
Assert.AreEqual(ple.PLArticleComment.Count(), count + 1);
//PLArticleComment newPlac = ple.PLArticleComment.First(m => m.Id == plac.Id);
//ple.Attach(newPlac);
acrep.Delete(plac);
Assert.AreEqual(ple.PLArticleComment.Count(), count + 1);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Every time i try to run this code, I get an exception in the delete statement, telling me that its not contained within the current ObjectStateManager.Please note that both my Save and delete looks like this:
public void Delete(PLCore.Model.PLArticleComment comment)
{
using (PortalLandEntities ple = Connection.GetEntityConnection())
{
ple.DeleteObject(comment);
ple.SaveChanges();
}
}
public void Save(PLCore.Model.PLArticleComment comment)
{
using (PortalLandEntities ple = Connection.GetEntityConnection())
{
ple.AddToPLArticleComment(comment);
ple.SaveChanges();
}
}
and the connection thingy:
public class Connection
{
public static PortalLandEntities GetEntityConnection()
{
return new PortalLandEntities();
}
}
Any ideas on what i could do to make it work?
You cannot load an entity from one ObjectContext (in your case, an ObjectContext is an instance of PortalLandEntities) and then delete it from another ObjectContext, unless you detach it from the first and attach it to the second. Your life will be much, much simpler if you use only one ObjectContext at a time. If you cannot do that, you must manually Detach and then Attach first, all the while keeping track of which entities are connected to which ObjectContext.
How to use DI with your Connection : make it non-static.
public class Connection
{
private PortalLandEntities _entities;
public PortalLandEntities GetEntityConnection()
{
return _entities;
}
public Connection(PortalLandEntities entities)
{
this._entities = entities;
}
}
Then use a DI container per request. Most people do this via a controller factory.
In C# I am able to create a class like this:
static class clsDBUtils
{
public static SQLiteCommand cmd;
public static SQLiteConnection conn;
public static String databaseFilePath;
public static bool getConnection()
{
}
}
Then anywhere in my namespace can use without initialization this way:
clsDBUtils.getConnection();
How can this be rewritten for Java?
I don't want to use:
clsDBUtils sqlutil= new clsDBUtils();
Basically the same way, just make a (normal) final class with a private contructor (prevents being able to do new) and add static members only.
public final class clsDBUtils {
public static SQLiteCommand cmd;
public static SQLiteConnection conn;
public static String databaseFilePath;
public static bool getConnection() {
}
private clsDBUtils() {}
}
Apart from the particular question/problem, it is bad practice to declare expensive and external resources like Connection, Statement and ResultSet as an instance variable, let alone as a static variable. Those resources doesn't have an endless lifetime and your application may break when the DB decides to timeout the connection because it hasn't been released back to the DB after use.
I can't imagine that it's done differently in C# (it would have been a bug in the application as well), but the normal JDBC idiom is that you acquire and close it in the shortest possible scope, thus already inside the very same method block. E.g.
public Entity find(Long id) throws SQLException {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
Entity entity = null;
try {
connection = database.getConnection();
statement = connection.prepareStatement(SQL_FIND);
statement.setLong(1, id);
resultSet = statement.executeQuery();
if (resultSet.next()) {
entity = new Entity();
entity.setProperty(resultSet.getObject("columnname"));
// etc..
}
} finally {
// Always free resources in reversed order.
if (resultSet != null) try { resultSet.close(); } catch (SQLException logOrIgnore) {}
if (statement != null) try { statement.close(); } catch (SQLException logOrIgnore) {}
if (connection != null) try { connection.close(); } catch (SQLException logOrIgnore) {}
}
return entity;
}
The database.getConnection() can however technically perfectly be made static like this:
public final class Database {
static {
try {
Class.forName("com.example.jdbc.Driver");
} catch (ClassNotFoundException e) {
throw new ExceptionInInitializerError(e);
}
}
private Database() {
// No need to instantiate this class.
}
public static Connection getConnection() {
DriverManager.getConnection("jdbc:example://localhost/dbname", "user", "pass");
}
}
so that you can use it as
connection = Database.getConnection();
(which you still really need to close in the finally block after use!)
However, this makes the connection source also really static. You cannot take benefit of polymorphism and/or inheritance anymore to switch between connection sources, such as a connection pool (to get better performance). To get more ideas/insights you may find this article useful
The code for it is almost exactly the same (same concept, slightly different syntax)
public class ClsDBUtils
{
public static SQLiteCommand cmd;
public static SQLiteConnection conn;
public static String databaseFilePath;
public static boolean getConnection()
{
}
}
// somewhere else
ClsDBUtils.getConnection();
Just declare a public class and use the 'static' modifier on your methods and fields. If you do not want it to be instantiated, use 'public final class '. Alternatively, you can use a singleton class.
You want to implement the Singleton pattern: http://en.wikipedia.org/wiki/Singleton_pattern
public class clsDBUtils {
private static final clsDBUtils INSTANCE = new clsDBUtils();
// Private constructor prevents instantiation from other classes
private clsDBUtils() {}
public static clsDBUtils getInstance() {
return INSTANCE;
}
public SQLiteCommand cmd;
public SQLiteConnection conn;
public String databaseFilePath;
public bool getConnection()
{
}
}
You can then use the following syntax on your class:
clsDBUtils.getInstance().getConnection();