after carefully researching for a solution to this strange problem that I have and accomplished nothing. I am pretty much desperated.
I am working on a MVC3 project.
I have a DB Context class like this:
//SpaceUpEntities.cs
public class SpaceUpEntities: DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Profile> Profiles { get; set; }
public DbSet<Venue> Venues { get; set; }
public DbSet<Room> Rooms { get; set; }
public DbSet<Category> Categories { get; set; }
public DbSet<Event> Events { get; set; }
public DbSet<Capacity> Capacities { get; set; }
public DbSet<VenueStatus> VenueStatuses { get; set; }
}
and I initialize DBContext when application start
//Global.asax.cs
protected void Application_Start()
{
Database.SetInitializer<SpaceUpEntities>(null);
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
RegisterDependencyInjection();
ModelBinders.Binders.DefaultBinder = new TrimModelBinder();
}
The problem occurs when I want to query/Insert/Update to the DB.
For example this piece of code
//SecurityRepository.cs
public RegisterFeedback Register(User user, Profile profile)
{
try
{
using (var entities = new SpaceUpEntities())
{
// Check existing email address
var emailExisted = entities.Users.FirstOrDefault(i => i.Email == user.Email);
//... So on
}
}
catch (Exception e)
{
Logger.Error(e);
return new RegisterFeedback(false, Messages.GeneralError);
}
}
After using (var entities = new SpaceUpEntities()) entities should have been initialized but I ended up with this error
Error Message:
Function evaluation disabled because a previous function evaluation
timed out. You must continue execution to reenable function
evaluation.
Initially, I thought it was a connection problem to my server, so I checked:
ConnectionString
SQL Server setting (SQL Server 2012)
Although I can hardly see why they are the cause of this problem since I took serveral methods to test my ConnectionString to find it has no issue.
Any help would certainly be appreciated.
Thank you in advance.
Thang Do
P/S: this is how I tested my connection string:
This is my connection string
I tested it with this
Make sure you are using the Initialization strategy which matches what you are trying to achieve. Database.SetInitializer<T>(...);
By having the line below in your App_Start method, I believe you may be bypassing initialization
Database.SetInitializer<SpaceUpEntities>(null);
Here are some options from an article on code first database initialization strategies that I hope will be helpful to you:
There are four different database Initialization strategies:
CreateDatabaseIfNotExists: This is default initializer. As name suggests, it will create the database if none exists as per the configuration. However, if you change the model class and then run the application with this initializer, then it will throw an exception.
DropCreateDatabaseIfModelChanges: This initializer drops an existing database and creates a new database, if your model classes (entity classes) have been changed. So you don’t have to worry about maintaining your database schema, when your model classes change.
DropCreateDatabaseAlways: As the name suggests, this initializer drops an existing database every time you run the application, irrespective of whether your model classes have changed or not. This will be useful, when you want fresh database, every time you run the application, while you are developing the application.
Custom DB Initializer: You can also create your own custom initializer, if any of the above don't satisfy your requirements or you want to do some other process that initializes the database using above initializer
Related
I have created a database system for a library, and when a user registers the program checks if they already have an account, but this is always returning false even when I can see in my DBMS that the record exists.
public static bool UserExists(string email)
{
using (var context = new LibraryDbContext())
{
if (context.Users.Any(d => d.Email == email))
{
return true;
}
else
{
return false;
}
}
}
Also, this is my Dbcontext class
public class LibraryDbContext : DbContext
{
public LibraryDbContext()
: base()
{
}
public DbSet<Book> Books { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<ReturnsLog> Returns { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseInMemoryDatabase("LibraryProjectDbo");
}
}
Typically issues like this when connecting to an existing database for the first time are due to EF being pointed at a database you don't expect. (I.e. creating one via Code First rather than connecting to your existing DB, or creating tables you don't expect.)
When using database first, you should always disable the Code First initialization:
public LibraryDbContext()
{
Database.SetInitializer<LibraryDbContext>(null);
}
This will generate an exception if the DbContext goes and tries to create a schema which will help direct you to the correction.
By default EF will be looking for a connection string called "LibraryDbContext" in your web.confing/.exe.config file in the runtime location. When using connection strings I generally like to be explicit with the connection string name to reflect a Database rather than the DbContext. Often I will utilize multiple contexts to split up behaviour in a system that all point to the same database. So for example I'd call the main database connection string something like "AppConnection" and pass that through the base constructor.
public LibraryDbContext()
: base ("AppConnection")
{
Database.SetInitializer<LibraryDbContext>(null);
}
Alternatively to test your connection out you can pass a Connection String itself to the base constructor.
When reading an entity type from my DataContext, I get all the associated objects when I don't want them. How do I set EF up so I only do explicit loading?
Reading up on msdn info like from here:
https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-2-2/
It seems like I should get nothing for free, so explicit loading is the way, however I'm using the code below but my results are more than I would expect.
public class TalesContext : DbContext
{
public TalesContext()
{
}
public TalesContext(DbContextOptions<TalesContext> options) : base(options)
{
}
protected internal DbSet<Story> Stories { get; set; }
protected internal DbSet<Event> Events { get; set; }
protected internal DbSet<StoryEventMention> EventMentions { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (optionsBuilder.IsConfigured) return;
optionsBuilder.UseInMemoryDatabase("TalesTesting");
}
}
public class Event
{
[Required]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public IList<StoryEventMention> EventMentions { get; set; }
[MaxLength(128)]
public string Title { get; set; }
}
var query = from e in TalesContext.Events select e;
// various query.Where
query = query.Skip((pageNumber - 1) * pageSize).Take(pageSize);
return query.ToList();
I would expect to get a list of Events with the Ids and Titles populated and EventMentions as null. However I get EventMentions populated along with all further navigation properties. Pretty much the entire test database.
I get this when I run a unit test and when I expose this through an API.
I found my mistake.
My EventFetcher class is a singleton, registered through IoC. It has a reference to TalesContext also registered as a singleton through IoC. So I had one DataContext through the application. So when the first request came in, it seeded the database - and so had everything in it. Thus all the references between the objects were already built and when I requested one without explicitly including it, the context returned the data it already had with everything attached.
I did a restructure on this so that a new context is injected into the controller each request and the behaviour is exactly what you would expect. So the lesson here is to be mindful of the age and persistence of your data context if you start getting unexpected results when querying.
Thanks for the assistance!
To answer your question. I believe what you need to do is
inside your TalesContext call this :
this.Configuration.LazyLoadingEnabled = false;
Sources:
explains lazy loading:
https://www.entityframeworktutorial.net/lazyloading-in-entity-framework.aspx
Explains the difference between eager loading and lazy loading
https://learn.microsoft.com/en-us/aspnet/mvc/overview/getting-started/getting-started-with-ef-using-mvc/reading-related-data-with-the-entity-framework-in-an-asp-net-mvc-application
After quite some digging and confusing error messages, I've arrived at this sample (which I believe to be the smallest example reproducing the issue). I can almost certainly conclude that the issue appears due to the entity linked to the one that I'm returning.
[OperationContract]
[WebGet(UriTemplate = "Stations")]
List<Station> GetStations();
public List<Station> GetStations()
{
List<Station> stations = new List<Station>();
using (Context context = new Context())
foreach (Station station in context.Stations.Include(element => element.Records))
//stations.Add(station.Copy());
stations.Add(station);
return stations;
}
It works if I activate the line with Copy() (which creates a new instance of a station and copies over all the properties except for the records, which it creates by itself). However, when I just add the stations without creating a copy (regardless of whether I keep the records, nullify them or set en empty list), it doesn't roll well.
Since I used Include(), the objects being disposed isn't the issue anymore. The error message I get says in the console like so.
http://localhost:25760/MyService.svc/Stations net::ERR_CONNECTION_RESET
Googling that gave me a lot of references to Apache (I'm running it on IIS), PHP (I'm building it on .NET) and security issues with certificates (I'm not using any and the other calls work well).
So my suspicion is either that the error message is misleading coming from a confused computer or that I'm missing something in my setup. The autogenerated classes reflect the foreign key I added to the tables and look like this.
alter table Records
add constraint FkStationId
foreign key (StationId)
references Stations (Id)
public partial class Record
{
public System.Guid Id { get; set; }
public Nullable<System.Guid> StationId { get; set; }
...
public virtual Station Station { get; set; }
}
public partial class Station
{
[System.Diagnostics.CodeAnalysis.SuppressMessage(
"Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Station() { this.Records = new HashSet<Record>(); }
public System.Guid Id { get; set; }
...
[System.Diagnostics.CodeAnalysis.SuppressMessage(
"Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Record> Records { get; set; }
}
I see nothing that leads me to any idea on how to trouble-shoot it. This error shouldn't happen. On the other hand - Fukushima shouldn't happen neither. But it did.
Finally I got this running.
Turn off proxy creation.
Turn off lazy loading.
Make virtual property ignorable to serialization.
Load in the linked entity explicitly.
The first two items are done in the constructor of the context.
public partial class Context : DbContext
{
public Context() : base("name=ContextConnection")
{
Configuration.LazyLoadingEnabled = false;
Configuration.ProxyCreationEnabled = false;
}
...
}
The third is done by attributing one of the virtual properties that lead to circular dependency as not valid for serialization.
public partial class Station
{
...
[IgnoreDataMemeber]
public virtual ICollection<Record> Records { get; set; }
}
The last one is including or omitting the navigational property to be (or not to be displayed). In this case, it made sense to jam in the information about stations into each record. The stations can be presented without the records, though.
public List<Station> GetStations()
{
using (Context context = new Context())
return context.Stations
.ToList();
}
public List<Record> GetRecords()
{
using (Context context = new Context())
return context.Records
.Include(record => record.Station)
.ToList();
}
Having said that, there will be dragons. This approach leads to a lot of work as it requires to manually re-edit the auto-generated files each time they're re-created. So i went with Code First, instead.
I've previously used NHibernate and Fluent Migrator in projects to create a database (if it didn't already exist) and update the schema through migration scripts. I'm looking over Entity Framework (6) to do a comparison and I'm having trouble replicating that functionality.
In my App.config, I've set up my connection string and db providers. I then went ahead and created a data model that I would like to be represented as a table in the database.
namespace DataModels
{
public class StoreClient
{
public int Id;
public string DisplayName;
public StoreClient()
{
}
}
}
I then went ahead and created a database context.
namespace DataModels
{
public class StoreContext : DbContext
{
public DbSet<StoreClient> StoreClients { get; set; }
}
}
On service start I created an instance of StoreContext and tried to add and call db.SaveChanges();, but this is failing because there is no schema that matches my StoreClient.
My question is simple. How do I configure my StoreContext (or EF in general) to automatically create my database schema, and how do I set it up to migrate when I make changes to that schema?
This seems simple, but my searching around hasn't gotten me anything that looks remotely familiar coming from the NHibernate world.
If you want your db to be created automatically try to put some code in your Application_Start() method.
for example:
Database.SetInitializer(new MigrateDatabaseToLatestVersion<StoreContext, Configuration>());
StoreContext context = new StoreContext();
context.Database.Initialize(true);
Where Configuration class is created upon automatic migrations are enables in the console. Check out this msdn demo.
Also i am not shure that your code firs model will work that way. If not try changing your fields with properties.
namespace DataModels
{
public class StoreClient
{
public int Id { get; set; }
public string DisplayName { get; set; }
public StoreClient()
{
}
}
}
Any help or advice regarding this issue is greatly appreciated.
I am currently working on a project that requires a change in our data layer from a local MS SQL instance to a hosted Oracle solution.
Previously, we were using Entity Framework (Code-First) to build our data layer. I would like to take the same approach with the new data layer. We have several applications that use this library, so trying to keep the new data layer as close to the same (objects, names, etc.) as the original would be ideal. I know that Code-First is not officially supported by Oracle (a work in progress), but have read where others have had some success. Thus, for these reasons, I am attempting to do the same.
I have created my Oracle EF data layer to match as closely as I can to the original MS SQL EF data layer. The issue that I'm currently having is that when I run a query to retrieve the first or default entity from the data layer, I get the following exception:
Oracle.DataAccess.Client.OracleException: ORA-00942: table or view does not exist
If I use the exact same DbContext instance and instead run a sql query using the DbContext.Database.SqlQuery(sqlString), it works. The reason I mention this is because I've read the "table or view does not exist" error refers to a database permissions issue. That does not appear to be the case this time, since I'm using the exact same connection string in the same connection object. The only difference appears to be in using traditional sql statements versus the DbSet entities (& configurations).
My entities are relatively simple, flat objects.
public class HourlyPrice
{
public DateTime MarketDate { get; set; }
public int HourEnding { get; set; }
public string LocationId { get; set; }
public string LocationName { get; set; }
public decimal? Price { get; set; }
public int IsValid { get; set; }
public DateTime DateInserted { get; set; }
public DateTime? DateUpdated { get; set; }
}
public HourlyPriceConfiguration(string viewName)
{
ToTable(viewName);
HasKey(x => new { x.MarketDate, x.HourEnding, x.LocationName });
Property(x => x.Price).HasPrecision(13, 6);
HasEntitySetName("SourceHourlyPrices");
}
Inside my DbContext, I add the HourlyPriceConfiguration injecting the viewName ...
modelBuilder.Configurations.Add(new HourlyPriceConfiguration(this.viewName));
... and declare my IDbSet as ...
public IDbSet<HourlyPrice> SourceHourlyPrices { get; set; }
When running the code, this works ...
var sql = "select * from " + this.viewName;
var prices = db.Database.SqlQuery<HourlyPrice>(sql);
var price = prices.FirstOrDefault();
... but this ...
var price = db.SourceHourlyPrices.FirstOrDefault();
... produces the "table or view does not exist" error.
Is this just an issue with the Code-First approach, or am I missing something here? When debugging the application, I can see the viewName being passed to the configuration class is the same that is being passed to the sql statement used in SqlQuery. I've tried removing the HasEntitySetName() and changing the IDbSet to the standard HourlyPrices, but that didn't work, either.
Thanks again, in advance.
I would like to confirm that I had the same problem with a table name.
In Oracle if the name is not full UPPER CASE the table/view is not found.
Code First Automatic Migrations is limited to working with the dbo schema only.
https://community.oracle.com/thread/3622163
You can put it in beginning OnModelCreating method of your Context class as a workaround.
if (this.Database.Connection.GetType().Equals(typeof(Oracle.ManagedDataAccess.Client.OracleConnection)))
{
modelBuilder.HasDefaultSchema(new Oracle.ManagedDataAccess.Client.OracleConnectionStringBuilder(this.Database.Connection.ConnectionString).UserID);
}
The ORA-00942 exception is not a permission issue (depends on how you look at it of course); but it means that the table you are querying is not visible to your user.
You may try to explicitly set the name of your schema in your ToTable method call by using the ToTable(tableName, schemaName) implementation and see what happens.
Just wanted to add that I had the same problem after moving the DB to a different schema. I realised that it is critically to have the schema name in upper case when using ToTable(tableName, schemaName).