I have an EF6 / ASP.NET 4.5 Webforms solution up and running, and now I need to add some functionality to allow bulk inserts from Excel files.
I am aware that EF out of the box isn't optimized for bulk operations, so I looked around and found "EF BulkInsert" (https://efbulkinsert.codeplex.com/) to facilitate just this.
I tried it in a test app, and it worked wonderfully - but when I included it in my actual main app, it broke down. When trying to do the actual bulk insert call, the system crashes with an exception:
BulkInsertProviderNotFoundException: BulkInsertProvider not found for 'Glimpse.Ado.AlternateType.GlimpseDbConnection. To register new provider use EntityFramework.BulkInsert.ProviderFactory.Register() method'
Now I'm unsure if this is the fault of Glimpse or EF BulkInsert (or both), and unfortunately, I cannot seem to find any solution - neither of the makers of these pieces of software is providing any insights or workarounds....
Has anyone here stumbled across this same problem, and found a solution for it??
This problem occurs because Glimpse wraps DbConnection and EF BulkInsert extension tries to access it's private field "_connectionString" which is not there.
I would blame EF BulkInsert in this case as accessing private members is just bad practice and no developer in Glimpse team could have anticipated that.
To solve this problem I have written a custom which inherits from EfSqlBulkInsertProviderWithMappedDataReader (default provider):
public class GlimpseProvider : EfSqlBulkInsertProviderWithMappedDataReader, IEfBulkInsertProvider
{
private static object GetPrivateFieldValue(object obj, string propName) {
if (obj == null) throw new ArgumentNullException("obj");
Type t = obj.GetType();
FieldInfo fieldInfo = null;
PropertyInfo propertyInfo = null;
while (fieldInfo == null && propertyInfo == null && t != null) {
fieldInfo = t.GetField(propName,
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (fieldInfo == null) {
propertyInfo = t.GetProperty(propName,
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
}
t = t.BaseType;
}
if (fieldInfo == null && propertyInfo == null)
throw new ArgumentOutOfRangeException("propName",
string.Format("Field {0} was not found in Type {1}", propName, obj.GetType().FullName));
if (fieldInfo != null)
return fieldInfo.GetValue(obj);
return propertyInfo.GetValue(obj, null);
}
protected override IDbConnection DbConnection {
get { return (IDbConnection)GetPrivateFieldValue(this.Context.Database.Connection, "InnerConnection"); }
}
}
Now Register this provider somewhere. I did it in context OnModelCreating method.
EntityFramework.BulkInsert.ProviderFactory.Register<GlimpseProvider>("Glimpse.Ado.AlternateType.GlimpseDbConnection");
Be aware that I've tested this only with basic usage of EF BulkInsert.
Related
I've started using Entity Framework (database first), and I noticed that the methods the tt template generates for the context class (for stored procedures) have a return type ofObjectResult.
This type is IDisposable, but no sample code I can find actually calls the Dispose method. Is there a reason for this?
I currently don't have the "using" on the stored procedure call as I do further IEnumerable related stuff on the result (essentially just projecting the result set), but I could easily refactor that.
My question is, should I be using a pattern like the following if I have no reason to keep the connection to the database open:
using (var context = new DatabaseContext())
{
using (var result = context.spMyStoredProcedure(param1, param2))
{
return result.ToList();
}
}
I've seen some advice that even disposing the DbContext might not be needed, but there seems to be a lot of inconsistencies even on MSDN on what to do.
I decompiled ObjectResult<T> (EF4.) Here's its Dispose() method. It's creating other managed objects, like a DbDataReader. and an internal object called a Shaper that can own a database connection.
If you dispose it, you're trusting it to know what it's doing. If you don't, you trust yourself to know what it's doing, not doing, and why. I'd play it safe and dispose it.
public override void Dispose()
{
DbDataReader reader = this._reader;
this._reader = (DbDataReader) null;
this._nextResultGenerator = (NextResultGenerator) null;
if (reader != null && this._readerOwned)
{
reader.Dispose();
if (this._onReaderDispose != null)
{
this._onReaderDispose((object) this, new EventArgs());
this._onReaderDispose = (Action<object, EventArgs>) null;
}
}
if (this._shaper == null)
return;
if (this._shaper.Context != null && this._readerOwned)
this._shaper.Context.ReleaseConnection();
this._shaper = (Shaper<T>) null;
}
I'm facing a strange problem with ASP.NET MemoryCaching in a MVC 3 ASP.NET application.
Each time an action is executed, I check if its LoginInfo are actually stored in the MemoryCache (code has been simplified, but core is as follow):
[NonAction]
protected override void OnAuthorization(AuthorizationContext filterContext) {
Boolean autorizzato = false;
LoginInfo me = CacheUtils.GetLoginData(User.Identity.Name);
if (me == null)
{
me = LoginData.UserLogin(User.Identity.Name);
CacheUtils.SetLoginInfo(User.Identity.Name, me);
}
// Test if the object is really in the memory cache
if (CacheUtils.GetLoginData(User.Identity.Name) == null) {
throw new Exception("IMPOSSIBLE");
}
}
The GetLoginInfo is:
public static LoginInfo GetLoginData(String Username)
{
LoginInfo local = null;
ObjectCache cache = MemoryCache.Default;
if (cache.Contains(Username.ToUpper()))
{
local = (LoginInfo)cache.Get(Username.ToUpper());
}
else
{
log.Warn("User " + Username + " not found in cache");
}
return local;
}
The SetLoginInfo is:
public static void SetLoginInfo (String Username, LoginInfo Info)
{
ObjectCache cache = MemoryCache.Default;
if ((Username != null) && (Info != null))
{
if (cache.Contains(Username.ToUpper()))
{
cache.Remove(Username.ToUpper());
}
cache.Add(Username.ToUpper(), Info, new CacheItemPolicy());
}
else
{
log.Error("NotFound...");
}
}
The code is pretty straightforward, but sometimes (totally randomly), just after adding the LoginInfo to the MemoryCache, this results empty, the just added Object is not present, therefore I got the Exception.
I'm testing this both on Cassini and IIS 7, it seems not related to AppPool reusability (enabled in IIS 7), I've tested with several Caching policies, but cannot make it work
What Am I missing/Failing ?
PS: forgive me for my bad english
Looking at the code for MemoryCache using a decomplier there is the following private function
private void OnUnhandledException(object sender, UnhandledExceptionEventArgs eventArgs)
{
if (!eventArgs.IsTerminating)
return;
this.Dispose();
}
There is an unhandled exception handler setup by every MemoryCache for the current domain Thread.GetDomain() so if there is ever any exception in your application that is not caught which may be common in a website it disposes the MemoryCache for ever and cannot be reused this is especially relevant for IIS apps as apposed to windows applications that just exit on unhanded exceptions.
The MemoryCache has limited size. For the Default instance, is't heuristic value (according to MSDN).
Have you tried to set Priority property on CacheItemPolicy instance to NotRemovable?
You can have race-condition because the Contains-Remove-Add sequence in SetLoginInfo is not atomic - try to use Set method instead.
Btw. you are working on web application so why not to use System.Web.Caching.Cache instead?
I believe you are running into a problem that Scott Hanselman identified as a .NET 4 bug. Please see here: MemoryCache Empty : Returns null after being set
Is it possible to get the EntityKey and type of an entity's parent entity without knowing the type? I've tried doing the following
public partial class TestEntities
{
partial void OnContextCreated()
{
this.SavingChanges += new EventHandler(logChanges);
}
void logChanges(object sender, EventArgs e)
{
IEnumerable<ObjectStateEntry> changes = this.ObjectStateManager.GetObjectStateEntries(
EntityState.Added |
EntityState.Deleted |
EntityState.Modified);
TestEntities context = sender as TestEntities;
foreach (ObjectStateEntry stateEntryEntity in changes)
{
if (!stateEntryEntity.IsRelationship && stateEntryEntity.Entity != null)
{
Audit audit = new Audit
{
AuditID = Guid.NewGuid()
};
foreach (var relationship in stateEntryEntity.RelationshipManager.GetAllRelatedEnds())
{
var parent = stateEntryEntity.RelationshipManager.GetRelatedCollection<EntityObject>(relationship.RelationshipName, relationship.TargetRoleName);
audit.Decription =
string.Format("{0} changed on {1} with id of {2}",stateEntryEntity.Entity, parent.GetType().Name);
}
context.AddToAudits(audit);
}
}
}
}
But I get the following.
An EntityCollection of EntityObject objects could not be returned for role name
'Canine' in relationship 'TestModel.FK_CANINE'. Make sure that the
EdmRelationshipAttribute that defines this relationship has the correct
RelationshipMultiplicity for this role name. For more information, see the
Entity Framework documentation.
I'm wondering if maybe I'm approaching this the worng way.
After search it isn't feasible to do what I wanted with EF. I wanted to crawl the inheritance tree for Auditing purposes. I ended up creating an Auditor interface that logs an audit message. I created Auditor implementations for the each EF entity type I wanted to audit. When the calling code asked for a class that implemented the Auditor interface I used named mappings from Microsoft Unity to inject the concrete class or avoid auditing if no mapping was found.
Using information from some of the questions here on generic views, I have created an MVC app that reads .dlls from its own /bin directory and builds the UI on the fly. InputBuilder partial views helped a lot. I also made a ControllerFactory, after the advice from here and elsewhere.
My problem is, while everything is working OK and reflection is recognizing the types I'm passing around, GetType() requires the full assembly qualified name ('scuse the code, still prototyping):
public IController CreateController(RequestContext requestContext, string controllerName)
{
Type controllerType = null;
Type genericType;
//controllerName coming in as full assembly-qualified path
Type baseControllerType = typeof(CoreDataController<>);
genericType = Type.GetType(controllerName);
if (genericType != null)
{
controllerType = baseControllerType.MakeGenericType(genericType);
}
if (controllerType != null)
{
return Activator.CreateInstance(controllerType) as IController;
}
return controllerType;
}
This makes my urls look like this:
http://localhost:1075/CoreData.Plans,%20PlansLib,%20Version=1.0.0.0,%20Culture=neutral,%20PublicKeyToken=null/Create
Obviously sub-optimal.
What I'd like is http://localhost:1075/CoreData.Plans/Create
or even better:
http://localhost:1075/Plans/Create
Should I store a dictionary accessible to my controller on Application_Start() mapping short names to fully-qualified names? Is there a feature of Reflection I'm missing that would solve this problem?
I think your idea of a dictionary mapping pretty names to types would be good. You may want to try putting attributes on your classes, then at startup, you can use reflection to extract out the attributes for building the dictionary:
[UrlName("my-class-name")]
public class MyClassName
{
// ...
}
I had this problem with long and even inconsistant type names across different platforms that i was using and came up with a way to search for the type in the dlls loaded in the current appdomain.
public static Type GetTypeFromName(string TypeNameStr, Assembly[] Asms)
{
Type VarType = null;
string TypeStr = TypeNameStr.Split(',')[0];
foreach (Assembly Dll in Asms)
{
VarType = Dll.GetType(TypeNameStr);
if (VarType == null)
VarType = Dll.GetType(TypeStr);
if (VarType != null)
break;
}
return VarType;
}
All that you need to do is pass the function a list of assemblies that you can get from the current appdomain and it will try to find the Type from there you can create a dictionary using the name and the type to cache this so that you don't have to do this over and over again.
I need to put a max length on my test field on my Views using ASP.NET MVC with the Entity Framework and I can't find how to get the max length of a varchar field.
Is there an easy way to get that, or any other property of a database field
Here is how i manage to do it (with an extension method on entities) :
public static int? GetMaxLength(this EntityObject entite, string nomPropriete)
{
int? result = null;
using (XEntities contexte = XEntities.GetCurrentContext())
{
var queryResult = from meta in contexte.MetadataWorkspace.GetItems(DataSpace.CSpace)
.Where(m => m.BuiltInTypeKind == BuiltInTypeKind.EntityType)
from p in (meta as EntityType).Properties
.Where(p => p.DeclaringType.Name == entite.GetType().Name
&& p.Name == nomPropriete
&& p.TypeUsage.EdmType.Name == "String")
select p.TypeUsage.Facets["MaxLength"].Value;
if (queryResult.Count() > 0)
{
result = Convert.ToInt32(queryResult.First());
}
}
return result;
}
Update
I realize that this answer doesn't directly apply to EF. At the time that I answered, there had been no answers for about 20 minutes and I thought knowing how I solved a similar problem with LINQToSQL might help. Given that the OP basically used the same technique albeit with EF properties instead, seems to indicate that I made the right choice. I'm leaving this answer here for context and for those who get here having the same problem but with LINQToSQL.
Original
I don't know about EF, but LINQToSQL entity properties are decorated with ColumnAttributes. You may be able to get the ColumnAttribute from the PropertyInfo for the property by looking at the CustomAttributesCollection. The value of this attribute would need to be parsed for length. I do that in my validator classes to make sure that I'm not going to get a SQL error by using a string that is too long for my column.
This is the method I use to extract the column length for string properties.
public static int MaximumPropertyLength( Type type, string propertyName )
{
int maximumLength = -1;
PropertyInfo info = type.GetProperty( propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance );
if (info != null)
{
var attribute = info.GetCustomAttributes( typeof( ColumnAttribute ), false )
.Cast<ColumnAttribute>()
.FirstOrDefault();
if (attribute != null)
{
maximumLength = ExtractLength( attribute.DbType );
}
}
return maximumLength;
}
private static int ExtractLength( string dbType )
{
int max = int.MaxValue;
if (dbType.Contains( "(" ))
{
string[] parts = dbType.Split( new char[] { '(', ')' }, StringSplitOptions.RemoveEmptyEntries );
if (parts.Length > 1)
{
int.TryParse( parts[1], out max );
}
}
return max;
}
For EntityFramework you would need to add your own custom attributes to the classes using a Code Generator or T4 Template.
Then what tvanfosson stated above would hold true. EF does not persist this information by default.
http://blogs.msdn.com/adonet/archive/2008/01/24/customizing-code-generation-in-the-ado-net-entity-designer.aspx
Explains more of what I am talking about with your code generator. It is pretty slick I have done exactly what you are mentioning before, problem is with proprietary code so I do not have an example for you.