I have several classes: User.cs, Permission.cs, and so on... all of them are children of BaseCore.cs where all the main logic is.
Here is my dbContext class (simplified):
public class MyContext : DbContext {
public MyContext() : base("AppEntityDB") {
System.Data.Entity.Database.SetInitializer(new DropCreateDatabaseAlways<MyContext>());
}
public virtual DbSet<User> Users { get; set; }
public virtual DbSet<Permissions> Permissions { get; set; }
}
Now I am creating baseListForm.cs that will be parent of all ListForms (windows form aplication)
I want baseListForm to have all basic functions like SaveData(); EditData() and LoadData();
Here is my BaseListForm class (simplified):
public partial class BaseListForm : Form {
private BaseCore _classType;
public virtual void LoadList() {
//I want here to load the collection of Mycontext() depending
// on what which class it calls. eg. if User.cs calls then i want
// to call DbSet<User> Users collection (accessible - _classType.Users)
var LoadCurrentClass = ClassType.
}
}
So I want to somehow select the corresponding collection from MyContext() for this.GetType(); class.
If you mean to say that 1 form has access to 1 dataset only then you can use generics.
You can add more functionalities other than my example. Normally you would create a repository or a unit of work class for CRUD operations on the database but this would restrict your form to access 1 DbSet. I hope you get the idea.
Form Base
public abstract class FormBase<T> : Form
where T : BaseCore
{
private ApplicationDbContext _db = new ApplicationDbContext();
/// <summary>
/// Accessor for the DbSet
/// </summary>
protected DbSet<T> DbSet
{
get { return _db.Set<T>(); }
}
/// <summary>
/// Inform the DbContext of the changes made on an entity
/// </summary>
/// <param name="entity"></param>
protected void UpdateEntry(T entity)
{
_db.Entry(entity).State = EntityState.Modified;
}
/// <summary>
/// Save changes on the DbContext
/// </summary>
protected void SaveData()
{
_db.SaveChanges();
}
}
User Form
public partial class frmUser : FormBase<User>
{
public frmUser()
{
InitializeComponent();
User user = this.DbSet.FirstOrDefault(); // Get first user record
user.Name = "New Name"; // Set new name value
this.UpdateEntry(user); // Inform DbContext that user has changed
this.SaveData(); // Save the changes made to the DbContext
}
}
Related
I have read the other questions regarding a matter similar to this, but it dosn't quite ask for a solution to this simple scenario:
namespace View
{
/// <summary>
/// Interaction logic for PuzzleSelectionScreen.xaml
/// </summary>
public partial class PuzzleSelectionScreen : Page
{
public PuzzleSelectionScreen(PuzzleControllerVM puzzleControllerVM, ScreenSwitcher screenSwitcher)
{
InitializeComponent();
// My button needs a command in screenSwitcher (View) to change Page ..
// .. with a Property (puzzle data) from puzzleControllerVM (View Model)
this.DataContext = puzzleControllerVM;
this.DataContext = screenSwitcher;
}
}
}
I can stick screenSwitcher in puzzleControllerVM and access all the properties just by this.DataContext = puzzleControllerVM;, but this would violate MVMM as screenSwitcher contains many View objects.
What I do above, the DataContext will assign to screenSwitcher only because it is executed last, but I want a convenient solution so my DataContext will have access to both sources without having to stick my screenSwitcher in my view model class PuzzleControllerVM.
U can create a new type which hold reference to both and set the datacontext to the instance of the type.
Something like this
public PuzzleSelectionScreen(PuzzleControllerVM puzzleControllerVM, ScreenSwitcher screenSwitcher)
{
InitializeComponent();
this.DataContext = new Hybrid { PuzzleControllerVM = puzzleControllerVM, ScreenSwitcher = screenSwitcher };
}
public class Hybrid
{
public PuzzleControllerVM PuzzleControllerVM { get; set; }
public ScreenSwitcher ScreenSwitcher { get; set; }
}
I have a class created by the entity framework (Document). It has a collection of another class (FileInfo).
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmEntityTypeAttribute(NamespaceName="DocumentManagerModel", Name="DocumentContainer")]
[Serializable()]
[DataContractAttribute(IsReference=true)]
public partial class DocumentContainer : EntityObject
{
...
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[XmlIgnoreAttribute()]
[SoapIgnoreAttribute()]
[DataMemberAttribute()]
[EdmRelationshipNavigationPropertyAttribute("DocumentManagerModel", "FK__FileInfo__00000000000018FA", "FileInfo")]
public EntityCollection<FileInfo> FileInfoes
{
get
{
return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedCollection<FileInfo>("DocumentManagerModel.FK__FileInfo__00000000000018FA", "FileInfo");
}
set
{
if ((value != null))
{
((IEntityWithRelationships)this).RelationshipManager.InitializeRelatedCollection<FileInfo>("DocumentManagerModel.FK__FileInfo__00000000000018FA", "FileInfo", value);
}
}
}
...
}
The user now can add or delete a item to the collection (FileInfos) through the gui. The gui form has a cancel button. How can I manage to reset all the changes at the collection?
As long as you didn't call dbcontext.SaveChanges() nothing is saved into the database. When they click the cancel button I'd just dispose the dbcontext and create a new one if I were you.
Calling
dbcontext.Entry(myEntity).CurrentValues.SetValues(dbcontext.Entry(myEntity).OriginalValues);
dbcontext.Entry(myEntity).State = EntityState.UnChanged;
should also do the trick.
I've got a small MVC webapplication running using Entity Framework 6. When starting the application by browwsing to the homepage (eg. www.mywebsite.dev) on my dev. machine the applicationpool get's started and the page get loaded as expected.
Despithe the fact that the homepage is pretty ligthweight and only get's a few things from the database (2 menu's, 2 paragraphs with text, and a collection with 3-4 objects) the application pool is already > 200 MB (!) after just loading the homepage once..
Using this and this article i've managed to figure out how to profile the manage memory, and I also removed a few static properties blocking the disposal of the context.
The DbContext has lazy loading disabled,
public class MyContext: DbContext
{
private readonly Dictionary<Type, EntitySetBase> _mappingCache = new Dictionary<Type, EntitySetBase>();
#region dbset properties
//Membership sets
public IDbSet<UserProfile> UserProfiles { get; set; }
public IDbSet<Project> Project { get; set; }
public IDbSet<Portfolio> Portfolio { get; set; }
public IDbSet<Menu> Menu { get; set; }
public IDbSet<MenuItem> MenuItem { get; set; }
public IDbSet<Page> Page { get; set; }
public IDbSet<Component> Component { get; set; }
public IDbSet<ComponentType> ComponentType { get; set; }
public IDbSet<BlogCategory> BlogCategory { get; set; }
public IDbSet<Blog> Blog { get; set; }
public IDbSet<Caroussel> Carousel { get; set; }
public IDbSet<CarouselItem> CarouselItem { get; set; }
public IDbSet<Redirect> Redirect { get; set; }
public IDbSet<TextBlock> TextBlock { get; set; }
public IDbSet<Image> Image { get; set; }
public IDbSet<ImageContent> ImageContent { get; set; }
#endregion
/// <summary>
/// The constructor, we provide the connectionstring to be used to it's base class.
/// </summary>
public MyContext() : base("name=MyConnectionstring")
{
//Disable lazy loading by default!
Configuration.LazyLoadingEnabled = false;
Database.SetInitializer<BorloContext>(null);
}
//SOME OTHER CODE
}
I still see a lot of objects in memory from which I expect they're related to entity framework's lazy loading.
I've setup the website with a few layers;
Controller - The usual stuff
Service - Trought a using statement used in the controllers. The services are disposable and contain a UnitOfWork. The UnitOfWork is initialized in the Constructor of the service and disposed when the service itsself get's disposed.
UnitOfWOrk - The UnitOfWork class contains a readonly private variable containing the context, together with a set of properties instantiating a Generic Repository of type T. Again, the UnitOfWork is disposable and it disposes the context when the Dispose method is called.
The Generic Repository matches an interface, takes the DbContext trought it's constructor and offers a basic set of methods trough an interface.
Below an example of how this is used.
PartialController
public class PartialController : BaseController
{
//private readonly IGenericService<Menu> _menuService;
//private readonly UnitOfWork _unitOfWork = new UnitOfWork();
//private readonly MenuService _menuService;
public PartialController()
{
//_menuService = new GenericService<Menu>();
//_menuService = new MenuService();
}
/// <summary>
/// Renders the mainmenu based on the correct systemname.
/// </summary>
[ChildActionOnly]
public ActionResult MainMenu()
{
var viewModel = new MenuModel { MenuItems = new List<MenuItem>() };
try
{
Menu menu;
using (var service = ServiceFactory.GetMenuService())
{
menu= service.GetBySystemName("MainMenu");
}
//Get the menuItems collection from somewhere
if (menu.MenuItems != null && menu.MenuItems.Any())
{
viewModel.MenuItems = menu.MenuItems.ToList();
return View(viewModel);
}
}
catch (Exception exception)
{
//TODO: Make nice function of this and decide throwing or logging.
if (exception.GetType().IsAssignableFrom(typeof(KeyNotFoundException)))
{
throw;
}
else
{
//TODO: Exception handling and logging
//TODO: If exception then redirect to 500-error page.
}
}
return View(viewModel);
}
}
ServiceFactory
public class ServiceFactory
{
public static IService<Menu> GetMenuService()
{
return new MenuService();
}
}
MenuService
public class MenuService : BaseService, IService<Menu>
{
private readonly UnitOfWork _unitOfWork;
private bool _disposed;
public MenuService()
{
if (_unitOfWork == null)
{
_unitOfWork = new UnitOfWork();
}
}
/// <summary>
/// Retrieves the menu by the provided systemname.
/// </summary>
/// <param name="systemName">The systemname of the menu.</param>
/// <returns>The menu if found. Otherwise null</returns>
public Menu GetBySystemName(string systemName)
{
var menu = new Menu();
if (String.IsNullOrWhiteSpace(systemName)) throw new ArgumentNullException("systemName","Parameter is required.");
if (Cache.HasItem(systemName))
{
menu = Cache.GetItem(systemName) as Menu;
}
else
{
var retrievedMenu = _unitOfWork.MenuRepository.GetSingle(m => m.SystemName.Equals(systemName), "MenuItems,MenuItems.Page");
if (retrievedMenu == null) return menu;
try
{
var exp = GenericRepository<CORE.Entities.MenuItem>.IsPublished();
var menuItems = (exp != null) ?
retrievedMenu.MenuItems.AsQueryable().Where(exp).Select(MenuTranslator.Translate).OrderBy(mi => mi.SortOrder).ToList() :
retrievedMenu.MenuItems.Select(MenuTranslator.Translate).OrderBy(mi => mi.SortOrder).ToList();
menu.MenuItems = menuItems;
}
catch (Exception)
{
//TODO: Logging
}
Cache.AddItem(systemName, menu, CachePriority.Default, CacheDuration.Short);
}
return menu;
}
public IEnumerable<Menu> Get()
{
throw new NotImplementedException();
}
~MenuService()
{
Dispose(false);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
_unitOfWork.Dispose();
}
}
_disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
GenericRepository
public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class, IEntityObject
{
///
/// The database context used.
///
internal MyContext Context;
/// <summary>
/// The loaded set of entities.
/// </summary>
internal DbSet<TEntity> DbSet;
/// <summary>
/// The constructor taking the databasecontext.
/// </summary>
/// <param name="context">The databasecontext to use.</param>
public GenericRepository(MyContext context)
{
//Apply the context
Context = context;
//Set the entity type for the current dbset.
DbSet = context.Set<TEntity>();
}
public IQueryable<TEntity> AsQueryable(bool publishedItemsOnly = true)
{
if (!publishedItemsOnly) return DbSet;
try
{
return DbSet.Where(IsPublished());
}
catch (Exception)
{
//TODO: Logging
}
return DbSet;
}
/// <summary>
/// Gets a list of items matching the specified filter, order by and included properties.
/// </summary>
/// <param name="filter">The filter to apply.</param>
/// <param name="includeProperties">The properties to include to apply eager loading.</param>
/// <param name="publishedItemsOnly">True if only publish and active items should be included, otherwise false.</param>
/// <returns>A collection of entities matching the condition.</returns>
public virtual IQueryable<TEntity> Get(Expression<Func<TEntity, bool>> filter, string includeProperties, bool publishedItemsOnly)
{
var query = AsQueryable(publishedItemsOnly);
if (filter != null)
{
query = query.Where(filter);
}
if (String.IsNullOrWhiteSpace(includeProperties))
return query;
//Include all properties to the dbset to enable eager loading.
query = includeProperties.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).Aggregate(query, (current, includeProperty) => current.Include(includeProperty));
return query;
}
}
To make a very long story short. What in my code / situation could possibly cause the problem that when loading just the homepage a amazing 200 MB or more is used? One strange thing i've noticed is that just before the page is loaded the memory jumps from 111 mb to 232 MB in the example below;
EDIT
Result from trace with dotMemory
EDIT 2
Below the results after i loaded the homepage. The homepage is now empty and in the global asax a single call to one service is made. I've kept the page open for a while and then refreshed, resulting in all the peaks.
Below a more detailed result, with apperently a lot of strings taking a lot of memory..?
EDIT 3
Different view from dotMemory
So, image is much more clearer now.
dotMemory displays, that your app takes only 9Mb of memory, we can see this on the Snapshot view. This is also confirmed by Memory Traffic view. ~73Mb was allocated from the beginning of profiling and ~65Mb was already collected to the Snapshot #1 point.
What about total memory usage displayed on the real time data chart, sorry I did not realized earlier then the most of your app memory usage is generation 0 heap. (And also I missed that your app uses only ~8Mb on the snapshot tile on this screen).
Gen 0 heap size displays the maximum bytes that can be allocated in
generation 0; it does not indicate the current number of bytes
allocated in generation 0.
http://msdn.microsoft.com/en-us/library/x2tyfybc(v=vs.110).aspx
Gen 0 heap size looks abnormally big for my taste, but it is an internal details of .net garbage collector, and it has a right to do that.
I have ventured to suggest that your app is running on the computer with big amount of RAM and/or with big CPU cache. But it can be also special aspects of ASP server implementation.
Conclusion - there is no problem with your app memory usage :) At least on loading just the homepage.
P.S. I would recommend to watch dotMemory video tutorials, in order to learn how to use it
I'm currently having an issue with explicit loading in Entity Framework.
I've disabled Proxy Creation and Lazy Loading in my datacontext.
public DataContext()
: base("")
{
Configuration.ProxyCreationEnabled = false;
Configuration.LazyLoadingEnabled = false;
}
This has been done because I need to be able to serialize my entity framework objects, which I cannot do when using virtual properties because this creates a virtual property.
I would like to retrieve the entity 'ContentType':
[Table("T_CONTENT_TYPES")]
public class ContentType : Entity
{
#region Properties
/// <summary>
/// Gets or sets the name of the content type.
/// </summary>
[Required]
[Column(Order = 1)]
public string Name { get; set; }
/// <summary>
/// Gets or sets the <see cref="Folder"/> in which this item belongs.
/// If this field is empty, it means that this item is stored in no particular folder, which means it's stored in the root.
/// </summary>
[Column(Order = 100)]
public Folder Folder { get; set; }
#endregion
}
This is done by using this code:
var contentType = UnitOfWork.ContentTypeRepository.GetById(Id);
As you see, my entity has a reference to a Folder. Since LazyLoading & Proxy Creation is disabled, I use the following code to retrieve the folder:
((DataContext) UnitOfWork.DataContext).Entry(contentType).Reference(x => x.Folder).Load();
My complete method is then:
public ContentType GetById(int Id)
{
var contentType = UnitOfWork.ContentTypeRepository.GetById(Id);
((DataContext) UnitOfWork.DataContext).Entry(contentType).Reference(x => x.Folder).Load();
return contentType;
}
The GetById method looks like the following:
public TEntity GetById(int id)
{
if (GetEntityById != null)
{ GetEntityById(this, new EventArgs()); }
var returnData = dbSet.FirstOrDefault(x => x.Id == id);
if (GetEntityByIdFound != null)
{ GetEntityByIdFound(this, new EventArgs()); }
return returnData;
}
However, the 'Folder' property is still null.
Anyone has an idea why this is not working?
If somebody knows a good working alternative for serializing lazy loaded entities, I'm prepared to integrate that one.
Can someone give me any help with this problem:
I have a database built with entity framework. In my simple project, all I'm trying to do is to add a new row in the database, that's all.
I have one class for the database, named UserDB
public class UserDB : DbContext
{
public UserDB()
: base("UserDB")
{
}
public List<User> Users { get; set; }
}
and class for the User
[Table(Name="User")]
public class User
{
[Key]
public String Name { get; set; }
}
I'm trying to add a new data in the database with another Console application, but every time I invoke the method insertInformation(string name) it says that the List of Users in UsersDB is null, and can't add the new User in the database. I used the same method in other ASP.NET application and it all work perfect. If someone have idea how to solve this, please help
The service I'm using:
public class Service1 : IService1
{
/// <summary>
/// Method for adding new User in Database
/// </summary>
/// <param name="name"></param>
public void insertData(string name)
{
UserDB db = new UserDB();
User user = new User
{
Name = name
};
//if (db.Users == null)
//{
// db.Users = new List<User>();
// db.Users.Add(user);
//}
//else
// db.Users.Add(user);
db.Users.Add(user);
db.SaveChanges();
}
Maybe you should try using the following code:
Instead of:
List<User> Users { get; set; }
Simply try:
DbSet<User> Users { get; set; }
I always use DbSet or IDbSet in my DBContext's and it always works.
Use this
db.Users.InsertAllOnSubmit(user);
db.SubmitChanges();
Instead of
db.Users.Add(user);
db.SaveChanges();
try this
db.AddObject("User", user);
db.SaveChanges();