asp mvc code first update model without lossing data - sql-server

I have the following DbContext:
namespace Tasks.Models
{
public class TaskDBInitializer : DropCreateDatabaseIfModelChanges<TasksContext>
{
protected override void Seed(TasksContext context)
{
var projects = new List<Projects>
{
new Projects{ Title="proTitle", Describe="proDescribe" },
};
projects.ForEach(p => context.Projects.Add(p));
context.SaveChanges();
base.Seed(context);;
}
}
public class TasksContext : DbContext
{
public TasksContext() : base("name=TaskDB")
{
Database.SetInitializer(new TaskDBInitializer());
}
public DbSet<Task> Task { get; set; }
public DbSet<Projects> Projects { set; get; }
}
}
I now want to add another model but don't want to lose data that exists within the current database.
How can I add a model to my DbContext without losing data?

Instead of using DropCreateDatabaseIfModelChanges<TContext> as your IDatabaseInitializer<TContext> use MigrateDatabaseToLatestVersion<TContext,TMigrationsConfiguration> which will determine changes within your DbContext then update your existing database to be compatible.
Here is an example of how to implement the MigrateDatabaseToLatestVersion initializer:
namespace Tasks.Models
{
public sealed class TaskDBConfiguration : DbMigrationsConfiguration<TasksContext>
{
public TaskDBConfiguration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = false;
}
protected override void Seed(TasksContext context)
{
var projects = new List<Projects>
{
new Projects { Title = "proTitle", Describe = "proDescribe" },
};
projects.ForEach(p => context.Projects.Add(p));
context.SaveChanges();
base.Seed(context);
}
}
public class TasksContext : DbContext
{
public TasksContext() : base("name=TaskDB")
{
Database.SetInitializer<TasksContext>(
new MigrateDatabaseToLatestVersion<TasksContext, TaskDBConfiguration>()
);
}
public DbSet<Task> Task { get; set; }
public DbSet<Projects> Projects { set; get; }
}
}

Related

Blazor Server App; Refresh in browser a property that is a class comes back nul

App: Blazor Server .NET 5
Using Entity Framework Core
DB; Azure SQL DB
All Ok except for if I refresh the browser, the Helper properties returned by GetActivitys() are null.
Does the Helper property in Activity need a tag?
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Activity> Activitys { get; set; }
public DbSet<Helper> Helpers { get; set; }
}
public class DataAccessService : IDataAccessService
{
private readonly ApplicationDbContext _context;
public DataAccessService(ApplicationDbContext context)
{
_context = context;
}
public async Task<List<Activity>> GetActivitys()
{
var list = await _context.Activitys.ToListAsync<Activity>();
return list;
}
}
public class Activity
{
[Key]
[Column("Id")]
[JsonPropertyName("Id")]
public int Id { get; set; }
[Column("Task")]
[Required]
[JsonPropertyName("Task")]
public string Task { get; set; }
[Column("Helper")]
[JsonPropertyName("Helper")]
public Helper Helper { get; set; }
}
public class Helper
{
[Key]
[Column("Id")]
[JsonPropertyName("Id")]
public int Id { get; set; }
[Column("Name")]
[Required]
[JsonPropertyName("Name")
}
If you want to include navigational properties after materializing your query via .ToListAsync(), you must add a chained method .Include(activity => activity.Helper) before materialization.

Create Viewmodel from Controller / Model. Populate lists from database

I'm working on my first WPF MVVM application. I created a database and wrote queries to fetch album names and song names. Now I want to fill a list in my View with the album names and a second list with corresponding songs. I'm new to c# and WPF. I'd like to know how a view model would like for my controller would look like.
My controller:
public class BandManagerController
{
private bandkramEntities _context;
public BandManagerController()
{
_context = new bandkramEntities();
}
public List<AlbumData> GetAlbumList()
{
return _context.albums
.Select(a => new AlbumData
{
AlbumID = a.AlbumID,
AlbumName = a.AlbumName,
})
.ToList();
}
public List<SongData> GetSongList(int albumID)
{
return _context.songs
.Where(s => s.AlbumID == albumID)
.Select(s => new SongData
{
SongID = s.SongID,
SongName = s.SongName
})
.ToList();
}
}
I created a helper class with the NotifyOfPropertyChange class and a song and album data class:
AlbumData.cs
public class AlbumData
{
public string AlbumName { get; set; }
public int AlbumID { get; set; }
}
SongData.cs
public class SongData
{
public string SongName { get; set; }
public int SongID { get; set; }
}
For a better overview I want to split my Viewmodel into 4 main parts.
SongViewModel.cs
public class SongViewModel : NotifyOfPropertyChange
{
public SongViewModel()
{
}
public string SongName { get; set; }
public int SongID { get; set; }
}
AlbumViewModel.cs
public class AlbumViewModel : NotifyOfPropertyChange
{
public AlbumViewModel()
{
}
public string AlbumName { get; set; }
public int AlbumID { get; set; }
}
SongListViewModel.cs
AlbumListViewModel.cs
I would like to know how 3. and 4. would have to look like to fill the album list with the album names and show corresponding songs in a second list.
With MVVM you would lose the controller and just have a ViewModel. There you would have your lists as such(including a notify property changed)
private ObservableCollection<SongData> _songList;
public ObservableCollection<SongData> SongList
{
get { return _songList; }
set { SetProperty(ref _songList, value, () => SongList); }
}
Then you would load this list at some point
public void LoadSongData(int albumID)
{
Using(YourContext _context = new YourContext)
{
SongList = new ObservableCollection(_context.songs
.Where(s => s.AlbumID == albumID)
.Select(s => new SongData
{
SongID = s.SongID,
SongName = s.SongName
})
.ToList());
}
}

EF6 codefirst slow startup

I'm in a scenario WPF MVVM EF code first.
All start my application I have to initialize the two databases, but lose 10 seconds each time to do everything. there is a way to speed up?
private void InitDb()
{
var sednaComuniContext = new SednaComuniContext();
sednaComuniContext.Database.Initialize(false);//slowly
if (String.IsNullOrEmpty(Ditta) || Ditta == "BaseDb") return;
var sednaContext = new SednaContext(dbHelper.CreateConnectionString(Ditta));
sednaContext.Database.Initialize(false);//slowly
}
SednaComuniContext:
public class SednaComuniContext : DbContext,IContext
{
public static DatabaseHelper dbHelper;
static string _connection;
public SednaComuniContext()
: base(CreateConnectionString())
{
}
private static string CreateConnectionString()
{
dbHelper = new DatabaseHelper();
return dbHelper.CreateConnectionString("ArchiviComuni");
}
public SednaComuniContext(string connString)
: base(connString)
{
_connection = connString;
if (!Database.Exists())
{
Database.Initialize(true);
}
}
public DbSet<ArticoliFamiglia> ArticoliFamiglia { get; set; }
public DbSet<ArticoliGruppo> ArticoliGruppo { get; set; }
public DbSet<Articoli> Articoli { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<SednaComuniContext, Configuration>());
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
SednaContext:
public class SednaContext : DbContext,IContext //IDbContext
{
public static DatabaseHelper dbHelper;
static string _connection;
public SednaContext()
: base(_connection)
{
}
public SednaContext(string connString)
: base(connString)
{
_connection = connString;
}
public DbSet<ArticoliFamiglia> ArticoliFamiglia { get; set; }
public DbSet<ArticoliFamigliaImpostazioni> ArticoliFamigliaImpostazioni { get; set; }
public DbSet<ArticoliGruppo> ArticoliGruppo { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<SednaContext, Configuration>());
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
Can an entity migration be used for that?
Since the Entity Framework team has moved to Entity Framework 6 to the EntityFramework.dll the initial load of the database slowed down considerably, some of these problems were fixed but building a model with 2 entities at a console project takes 4-5 seconds for me as well. See this open item describing part of this problem:
http://entityframework.codeplex.com/workitem/2298
The only workaround for this would be a loading screen where you show the users some fancy progress bar and display terms like loading this and that important part of the application.

What is the right way to save and restore a disconnected entity using code first?

So that I can store the user's screen preferences, I have ScreenSettings entity that I want to retrieve when the program starts and save when the program ends.
For this reason I don't want to keep the context open.
I am wondering about the best way to do this.
I have tried the following
however I am not comfortable with the SaveSettings function because it deletes and re-adds the object.
How do I save changes to the object without actually replacing it?
namespace ClassLibrary1
{
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
//Domain Class
public class ScreenSetting
{
#region Properties
public int Id { get; set; }
[Required]
public int WindowLeft { get; set; }
[Required]
public int WindowTop { get; set; }
#endregion
}
// Context
public class Context : DbContext
{
#region Properties
public DbSet<ScreenSetting> ScreenSettings { get; set; }
#endregion
}
// UI
public class UI
{
#region Public Methods
// Get the settings object
public ScreenSetting GetSettings(int SettingsId)
{
var Db = new Context();
ScreenSetting settings = Db.ScreenSettings.Find(SettingsId);
if (settings == null)
{
settings = new ScreenSetting { Id = SettingsId, WindowTop = 100, WindowLeft = 100 };
Db.ScreenSettings.Add(settings);
}
Db.Dispose();
return settings;
}
// Save the settings object
public void SaveSettings(ScreenSetting settings)
{
var Db = new Context();
ScreenSetting oldSettings = Db.ScreenSettings.Find(settings.Id);
if (oldSettings == null)
{
Db.ScreenSettings.Add(settings);
}
else
{
Db.ScreenSettings.Remove(oldSettings);
Db.ScreenSettings.Add(settings);
}
Db.Dispose();
}
public void test()
{
ScreenSetting setting = this.GetSettings(1);
setting.WindowLeft = 500;
setting.WindowTop = 500;
this.SaveSettings(setting);
}
#endregion
#region Methods
private static void Main()
{
var o = new UI();
o.test();
}
#endregion
}
}
You ran into a common pattern, update or insert, which is so common that it's got a name: upsert. When a pattern is common, usually there also is a common solution.
In System.Data.Entity.Migrations there is an extension method AddOrUpdate that does exactly what you want:
public void SaveSettings(ScreenSetting settings)
{
using (var db = new Context())
{
db.ScreenSettings.AddOrUpdate(settings);
db.SaveChanges();
}
}

Ria Service: Navigation Property is null

For example I have two entities
Class A
{
public Guid Id {get;set;}
public Guid BId {get;set;}
public B InstanceB {get;set;}
}
Class B
{
public Guid Id {get;set}
}
B is related to A, on my silver light application I am creating a new instance of A, and also a new instance of B. The new instance of B does not exist yet. But I need the instance of B on my service.
Can I do this without Entity or Association with Ria Service?
Edit:
My Class A :
public partial class lSync{
// Metadata classes are not meant to be instantiated.
private lSync() {
}
public string ConflictMessage { get; set; }
public DateTime DateInserted { get; set; }
public Guid vValuesId { get; set; }
public Guid ID { get; set; }
public bool IsConflict { get; set; }
public bool IsReadyToSync { get; set; }
public Guid SyncSet { get; set; }
public vValues vValues { get; set; }
}
My Ria Service:
[Invoke]
public lSync[] SynchvValuesFromClient(lSync[] syncs) {
bool noConflict = true;
foreach (lSync sync in syncs) {
var servervValue = GetvValuesByID(sync.vValuesId).FirstOrDefault();
var queuevValues = sync.vValues; //sync.vValues here is null, but my sync.vValuesId is not
if (servervValue== null) {
InsertvValues(queueValue);
}
else {
if (servervValue.IsServerConflict(queueValue)) {
sync.IsConflict = true;
sync.ConflictMessage = "Conflict";
noConflict = false;
break;
}
if (!servervValue.AreValuesEqual(queueValue)) {
UpdatevValues(queueValue);
}
}
}
if (noConflict) {
this.ObjectContext.SaveChanges();
}
return syncs;
}
public IQueryable<vValues> GetvValuesByID(Guid ID) {
return ObjectContext.vValues.Where(t => t.ID == ID);
}
public void InsertvValues(vValues model) {
model.ServerDate = DateTime.UtcNow;
if ((model.EntityState != EntityState.Detached)) {
this.ObjectContext.ObjectStateManager.ChangeObjectState(model, EntityState.Added);
}
else {
this.ObjectContext.vValues.AddObject(model);
}
}
public void UpdatevValues(vValuesmodel) {
model.ServerDate = DateTime.UtcNow;
this.ObjectContext.vValues.AttachAsModified(model, this.ChangeSet.GetOriginal(model));
}
:(
Edit
The order is wrong of your method :)
Make an instance of the service before creating instances of the Entities.
It should be:
public void SyncToServer() {
ContextService service = new ContextService();
var instanceA = new A();
instanceA.InstanceB = new B();
service.SubmitChanges(); //service.SaveChanges() for LinqToEntities
}
Are you reloading after a submit because only adding the [Include] attribute in the DomainService MetaData won't work. You need to do this in the DomainService for LinqToSql
public A GetA()
{
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<A>(a => a.InstanceB);
this.DataContext.LoadOptions = dlo;
return this.DataContext.APlural.FirstOrDefault( ); //don't know the plural of A.
}
LinqToEntities:
public A GetA()
{
return this.MyEntitiesContext.APlural.Include( "instanceB" ).FirstOrDefault( ); //don't know the plural of A.
}
var a = new A(){
B = new B(); //or (B)selectedItem
}
now a.Id and a.BId is 0 until you SaveChanged and return saved A

Resources