1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

C# learning and getting in to a right pickle ..

Discussion in 'HTML, Graphics & Programming' started by darkgen, Apr 18, 2019.

  1. darkgen

    Wise Guy

    Joined: Mar 8, 2005

    Posts: 2,309

    Location: London, UK

    So I have been mucking about with the CU tutorial and am now attempting to mimic the CourseAssignment step using a dB generated primary key for the CourseID value instead of user defined one.

    So in my example,
    Student=Applications
    Course=IndApp (individual applications)
    CourseAssignment=AppAssignments

    In effect; Applications is the solution name, where IndApp contains separate vendor applications presented to the solution.

    However; when I attempt to seed the database it throws a wobbly. The error may appear pretty self-explanatory but I'm at a loss where to start.

    As far as I can fathom; the AppAssignments table is created correctly and my classes are set correctly. Any pointers would be most welcome.


    Code:
    SELECT [t].[ID] FROM [Application] t
    INNER JOIN @inserted0 i ON ([t].[ID] = [i].[ID])
    ORDER BY [i].[_Position];
    Microsoft.EntityFrameworkCore.Database.Command:Information: Executed DbCommand (8ms) [Parameters=[@p0='?' (Size = 50), @p1='?' (Size = 50)], CommandType='Text', CommandTimeout='30']
    SET NOCOUNT ON;
    INSERT INTO [IndApp] ([Application], [Version])
    VALUES (@p0, @p1);
    SELECT [ID]
    FROM [IndApp]
    WHERE @@ROWCOUNT = 1 AND [ID] = scope_identity();
    Microsoft.EntityFrameworkCore.Database.Command:Information: Executed DbCommand (1ms) [Parameters=[@p0='?' (Size = 50), @p1='?' (Size = 50)], CommandType='Text', CommandTimeout='30']
    SET NOCOUNT ON;
    INSERT INTO [IndApp] ([Application], [Version])
    VALUES (@p0, @p1);
    SELECT [ID]
    FROM [IndApp]
    WHERE @@ROWCOUNT = 1 AND [ID] = scope_identity();
    Microsoft.EntityFrameworkCore.Database.Command:Information: Executed DbCommand (0ms) [Parameters=[@p0='?' (Size = 50), @p1='?' (Size = 50)], CommandType='Text', CommandTimeout='30']
    SET NOCOUNT ON;
    INSERT INTO [IndApp] ([Application], [Version])
    VALUES (@p0, @p1);
    SELECT [ID]
    FROM [IndApp]
    WHERE @@ROWCOUNT = 1 AND [ID] = scope_identity();
    Exception thrown: 'System.InvalidOperationException' in Microsoft.EntityFrameworkCore.dll
    'iisexpress.exe' (CoreCLR: clrhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.2.3\System.Diagnostics.StackTrace.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
    'iisexpress.exe' (CoreCLR: clrhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.2.3\System.Reflection.Metadata.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
    'iisexpress.exe' (CoreCLR: clrhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.2.3\System.Text.Encoding.Extensions.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
    Tracker.Program:Error: An error occurred while seeding the database.
    
    System.InvalidOperationException: The instance of entity type 'AppAssignment' cannot be tracked because another instance with the same key value for {'IndAppID', 'ApplicationID'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.
       at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.ThrowIdentityConflict(InternalEntityEntry entry)
       at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.Add(TKey key, InternalEntityEntry entry, Boolean updateDuplicate)
       at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.Add(TKey key, InternalEntityEntry entry)
    .......
    
    Code:
    CREATE TABLE [dbo].[AppAssignment] (
        [ApplicationID] INT NOT NULL,
        [IndAppID]      INT NOT NULL,
        CONSTRAINT [PK_AppAssignment] PRIMARY KEY CLUSTERED ([IndAppID] ASC, [ApplicationID] ASC),
        CONSTRAINT [FK_AppAssignment_Application_ApplicationID] FOREIGN KEY ([ApplicationID]) REFERENCES [dbo].[Application] ([ID]) ON DELETE CASCADE,
        CONSTRAINT [FK_AppAssignment_IndApp_IndAppID] FOREIGN KEY ([IndAppID]) REFERENCES [dbo].[IndApp] ([ID]) ON DELETE CASCADE
    );
    
    
    GO
    CREATE NONCLUSTERED INDEX [IX_AppAssignment_ApplicationID]
        ON [dbo].[AppAssignment]([ApplicationID] ASC);
    Code:
    using Tracker.Models;
    using System;
    using System.Linq;
    using Microsoft.EntityFrameworkCore;
    using Microsoft.Extensions.DependencyInjection;
    
    namespace Tracker.Data
    {
        public static class DbInitializer
        {
            public static void Initialize(TrackerContext context)
            {
                //context.Database.EnsureCreated();
    
                // Look for any students.
                if (context.Applications.Any())
                {
                    return;   // DB has been seeded
                }
    
                var Applications = new Application[]
                {
                new Application{CTXApp="FirstApp",FirstMidName="Carson",LastName="Alexander",BusinessUnit="GMS",EnrollmentDate=DateTime.Parse("2005-09-01")},
                new Application{CTXApp="GCMS",FirstMidName="Meredith",LastName="Alonso",BusinessUnit="GMS",EnrollmentDate=DateTime.Parse("2002-09-01")},
                new Application{CTXApp="Oracle",FirstMidName="Arturo",LastName="Anand",BusinessUnit="GMS",EnrollmentDate=DateTime.Parse("2003-09-01")},
                new Application{CTXApp="Empower",FirstMidName="Gytis",LastName="Barzdukas",BusinessUnit="GMS",EnrollmentDate=DateTime.Parse("2002-09-01")},
                new Application{CTXApp="TCSDesktop",FirstMidName="Yan",LastName="Li",BusinessUnit="GMS",EnrollmentDate=DateTime.Parse("2002-09-01")},
                new Application{CTXApp="Documentum",FirstMidName="Peggy",LastName="Justice",BusinessUnit="GMS",EnrollmentDate=DateTime.Parse("2001-09-01")},
                new Application{CTXApp="OneCDS",FirstMidName="Laura",LastName="Norman",BusinessUnit="GMS",EnrollmentDate=DateTime.Parse("2003-09-01")},
                new Application{CTXApp="Access",FirstMidName="Nino",LastName="Olivetto",BusinessUnit="GMS",EnrollmentDate=DateTime.Parse("2005-09-01")}
                };
                foreach (Application a in Applications)
                {
                    context.Applications.Add(a);
                }
                context.SaveChanges();
    
                /*var IndApps = new IndApp[]
                {
                new IndApp{IndAppID=1050,Title="Chemistry",Credits=3},
                new IndApp{IndAppID=4022,Title="Microeconomics",Credits=3},
                new IndApp{IndAppID=4041,Title="Macroeconomics",Credits=3},
                new IndApp{IndAppID=1045,Title="Calculus",Credits=4},
                new IndApp{IndAppID=3141,Title="Trigonometry",Credits=4},
                new IndApp{IndAppID=2021,Title="Composition",Credits=3},
                new IndApp{IndAppID=2042,Title="Literature",Credits=4}
                };
                foreach (IndApp ia in IndApps)
                {
                    context.IndApps.Add(ia);
                }
                context.SaveChanges();*/
    
                var IndApps = new IndApp[]
               {
                new IndApp{Application="Access",Version="1"},
                new IndApp{Application="Excel",Version="2"},
                new IndApp{Application="Word",Version="3"}
               };
                foreach (IndApp ia in IndApps)
                {
                    context.IndApps.Add(ia);
                }
                context.SaveChanges();
    
    
                var AppAssignments = new AppAssignment[]
                {
                new AppAssignment {
                        IndAppID = IndApps.Single(ia => ia.Application == "Access" ).ID,
                        ApplicationID = Applications.Single(a => a.CTXApp == "FirstApp").ID
                        },
                new AppAssignment {
                        IndAppID = IndApps.Single(ia => ia.Application == "Excel" ).ID,
                        ApplicationID = Applications.Single(a => a.CTXApp == "GCMS").ID
                        },
                new AppAssignment {
                        IndAppID = IndApps.Single(ia => ia.Application == "Excel" ).ID,
                        ApplicationID = Applications.Single(a => a.CTXApp == "FirstApp").ID
                        },
                new AppAssignment {
                        IndAppID = IndApps.Single(ia => ia.Application == "Word" ).ID,
                        ApplicationID = Applications.Single(a => a.CTXApp == "FirstApp").ID
                        },
                new AppAssignment {
                        IndAppID = IndApps.Single(ia => ia.Application == "Word" ).ID,
                        ApplicationID = Applications.Single(a => a.CTXApp == "Oracle").ID
                        },
                new AppAssignment {
                        IndAppID = IndApps.Single(ia => ia.Application == "Word" ).ID,
                        ApplicationID = Applications.Single(a => a.CTXApp == "Empower").ID
                        },
                new AppAssignment {
                        IndAppID = IndApps.Single(ia => ia.Application == "Excel" ).ID,
                        ApplicationID = Applications.Single(a => a.CTXApp == "TCSDesktop").ID
                        },
                new AppAssignment {
                        IndAppID = IndApps.Single(ia => ia.Application == "Word" ).ID,
                        ApplicationID = Applications.Single(a => a.CTXApp == "Documentum").ID
                        },
                new AppAssignment {
                        IndAppID = IndApps.Single(ia => ia.Application == "Access" ).ID,
                        ApplicationID = Applications.Single(a => a.CTXApp == "OneCDS").ID
                        },
                new AppAssignment {
                        IndAppID = IndApps.Single(ia => ia.Application == "Word" ).ID,
                        ApplicationID = Applications.Single(a => a.CTXApp == "Empower").ID
                        }
                        };
    
                foreach (AppAssignment aa in AppAssignments)
                {
                    context.AppAssignments.Add(aa);
                }
                context.SaveChanges();
                /*
                var enrollments = new Enrollment[]
                {
                new Enrollment{ApplicationID=1,IndAppID=1050,Grade=Grade.A},
                new Enrollment{ApplicationID=1,IndAppID=4022,Grade=Grade.C},
                new Enrollment{ApplicationID=1,IndAppID=4041,Grade=Grade.B},
                new Enrollment{ApplicationID=2,IndAppID=1045,Grade=Grade.B},
                new Enrollment{ApplicationID=2,IndAppID=3141,Grade=Grade.F},
                new Enrollment{ApplicationID=2,IndAppID=2021,Grade=Grade.F},
                new Enrollment{ApplicationID=3,IndAppID=1050},
                new Enrollment{ApplicationID=4,IndAppID=1050},
                new Enrollment{ApplicationID=4,IndAppID=4022,Grade=Grade.F},
                new Enrollment{ApplicationID=5,IndAppID=4041,Grade=Grade.C},
                new Enrollment{ApplicationID=6,IndAppID=1045},
                new Enrollment{ApplicationID=7,IndAppID=3141,Grade=Grade.A}
                };
                foreach (Enrollment e in enrollments)
                {
                    context.Enrollments.Add(e);
                }
                context.SaveChanges(); */
            }
        }
    }
    Code:
    using Tracker.Models;
    using Microsoft.EntityFrameworkCore;
    using Microsoft.AspNetCore.Http;
    
    namespace Tracker.Data
    {
        public class TrackerContext : DbContext
        {
            public TrackerContext(DbContextOptions<TrackerContext> options) : base(options)
            {
            }
    
            public DbSet<IndApp> IndApps { get; set; }
            public DbSet<Enrollment> Enrollments { get; set; }
            public DbSet<Application> Applications { get; set; }
            public DbSet<AppAssignment> AppAssignments { get; set; }
    
            protected override void OnModelCreating(ModelBuilder modelBuilder)
            {
                modelBuilder.Entity<IndApp>().ToTable("IndApp");
                //modelBuilder.Entity<IndApp>().ToTable("IndApp2");
                modelBuilder.Entity<Enrollment>().ToTable("Enrollment");
                modelBuilder.Entity<Application>().ToTable("Application");
                modelBuilder.Entity<AppAssignment>().ToTable("AppAssignment");
    
    
                modelBuilder.Entity<AppAssignment>()
                   .HasKey(c => new { c.IndAppID, c.ApplicationID });
    
            }
        }
    }
    Code:
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    
    namespace Tracker.Models
    {
        public class Application
        {
            public int ID { get; set; }
            [Required]
            [StringLength(50, MinimumLength = 1)]
            [RegularExpression(@"^[A-Z]+[a-zA-Z""'\s-]*$")]
            [Display(Name = "Citrix Application")]
            public string CTXApp { get; set; }
            [Required]
            [StringLength(50, MinimumLength = 1)]
            [RegularExpression(@"^[A-Z]+[a-zA-Z""'\s-]*$")]
            [Display(Name = "Last Name")]
            public string LastName { get; set; }
            [StringLength(50, MinimumLength = 1)]
            [RegularExpression(@"^[A-Z]+[a-zA-Z""'\s-]*$")]
            [Column("FirstName")]
            [Display(Name = "First Name")]
            public string FirstMidName { get; set; }
            [Required]
            [StringLength(3, MinimumLength = 1)]
            [RegularExpression(@"^[A-Z]+[a-zA-Z""'\s-]*$")]
            [Display(Name = "Business Unit")]
            public string BusinessUnit { get; set; }
            [DataType(DataType.Date)]
            [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
            public DateTime EnrollmentDate { get; set; }
            [Display(Name = "Full Name")]
            public string FullName
            {
                get
                {
                    return LastName + ", " + FirstMidName;
                }
            }
            public ICollection<AppAssignment> AppAssignments { get; set; }
        }
    }
    Code:
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.ComponentModel.DataAnnotations;
    
    namespace Tracker.Models
    {
        public class IndApp
        {
            public int ID { get; set; }
            [Required]
            [StringLength(50, MinimumLength = 1)]
            [RegularExpression(@"^[A-Z]+[a-zA-Z""'\s-]*$")]
            [Display(Name = "Application")]
            public string Application { get; set; }
            [Required]
            [StringLength(50, MinimumLength = 1)]
            [RegularExpression(@"^[A-Z]+[a-zA-Z""'\s-]*$")]
            [Display(Name = "Version")]
            public string Version { get; set; }
            public ICollection<AppAssignment> AppAssignments { get; set; }
        }
    }
    Code:
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    
    namespace Tracker.Models
    {
        public class AppAssignment
        {
            public int ApplicationID { get; set; }
            public int IndAppID { get; set; }
            public Application Application { get; set; }
            public IndApp IndApp { get; set; }
        }
    }
    Cheers, Paul.
     
  2. touch

    Capodecina

    Joined: Oct 28, 2006

    Posts: 10,993

    Location: Sufferlandria

    You've got you're table setup correctly, the primary key is a clustered key of both ApplicationID and IndAppID fields. That means you can have duplicates in either field but not in both fields at the same time.

    So the issue is this section in DbInitializer.cs which is duplicated twice:
    Code:
    new AppAssignment {
                       IndAppID = IndApps.Single(ia => ia.Application == "Word" ).ID,
                        ApplicationID = Applications.Single(a => a.CTXApp == "Empower").ID
                        }
     
  3. darkgen

    Wise Guy

    Joined: Mar 8, 2005

    Posts: 2,309

    Location: London, UK

    Gracious me. Thank you. A complete wood for the trees moment!
     
  4. darkgen

    Wise Guy

    Joined: Mar 8, 2005

    Posts: 2,309

    Location: London, UK

    So next hiccup.

    As per this section I'm now trying to add/remove elements.

    The solution builds successfully but will throw out the following error when editing an application.
    Code:
    ArgumentNullException: Value cannot be null. Parameter name: source
    
    System.Linq.Enumerable.Select<TSource, TResult>(IEnumerable<TSource> source, Func<TSource, TResult> selector)
    
    
    Tracker.Controllers.ApplicationsController.PopulateAssignedAppData(Application application) in ApplicationsController.cs
    -
    179.            return View(application);
    180.        }
    181.
    182.        private void PopulateAssignedAppData(Application application)
    183.        {
    184.            var allindapps = _context.IndApps;
    185.            var CTXAppsApps = new HashSet<int>(application.AppAssignments.Select(c => c.IndAppID));
    186.            var viewModel = new List<AssignedIndAppData>();
    187.            foreach (var indApp in allindapps)
    188.            {
    189.                viewModel.Add(new AssignedIndAppData
    190.                {
    191.                    IndAppID = indApp.ID,
    
    
    Tracker.Controllers.ApplicationsController.Edit(Nullable<int> id) in ApplicationsController.cs
    -
    172.            if (application == null)
    173.
    174.
    175.            {
    176.                return NotFound();
    177.            }
    178.            PopulateAssignedAppData(application);
    179.            return View(application);
    180.        }
    181.
    182.        private void PopulateAssignedAppData(Application application)
    183.        {
    184.            var allindapps = _context.IndApps;
    
    
    Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor+TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, object controller, object[] arguments)
    
    
    System.Threading.Tasks.ValueTask<TResult>.get_Result()
    
    
    Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync()
    
    
    Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync()
    
    
    Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
    
    
    Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
    
    
    Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
    
    
    Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
    
    
    Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
    
    
    Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
    
    
    Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
    
    
    Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
    
    
    Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
    
    
    Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext)
    
    
    Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
    
    
    Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
    
    Code:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.Rendering;
    using Microsoft.EntityFrameworkCore;
    using Tracker.Data;
    using Tracker.Models;
    using Tracker.Models.TrackerViewModels;
    
    namespace Tracker.Controllers
    {
        public class ApplicationsController : Controller
        {
            private readonly TrackerContext _context;
    
            public ApplicationsController(TrackerContext context)
            {
                _context = context;
            }
    
            // GET: Applications
            public async Task<IActionResult> Index(int? id, int? indappID,
                string sortOrder,
                string currentFilter,
                string searchString,
                int? pageNumber)
            {
                ViewData["CurrentSort"] = sortOrder;
                ViewData["NameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
                ViewData["DateSortParm"] = sortOrder == "Date" ? "date_desc" : "Date";
    
                if (searchString != null)
                {
                    pageNumber = 1;
                }
                else
                {
                    searchString = currentFilter;
                }
    
    
    
                ViewData["CurrentFilter"] = searchString;
    
                var Applications = from a in _context.Applications
                                   select a;
    
                if (!String.IsNullOrEmpty(searchString))
                {
                    Applications = Applications.Where(s => s.LastName.Contains(searchString)
                                           || s.FirstMidName.Contains(searchString));
                }
    
                switch (sortOrder)
                {
                    case "name_desc":
                        Applications = Applications.OrderByDescending(a => a.LastName);
                        break;
                    case "Date":
                        Applications = Applications.OrderBy(a => a.EnrollmentDate);
                        break;
                    case "date_desc":
                        Applications = Applications.OrderByDescending(a => a.EnrollmentDate);
                        break;
                    default:
                        Applications = Applications.OrderBy(a => a.LastName);
                        break;
                }
    
                var viewModel = new ApplicationIndexData();
                viewModel.Applications = await _context.Applications
                      .Include(i => i.AppAssignments)
                        .ThenInclude(i => i.Application)
                      //      .ThenInclude(i => i.CTXApp)
                      .OrderBy(i => i.LastName)
                      .ToListAsync();
    
                if (id != null)
                {
                    ViewData["ApplicationID"] = id.Value;
                    Application application = viewModel.Applications.Where(
                        i => i.ID == id.Value).Single();
                    viewModel.IndApps = application.AppAssignments.Select(s => s.IndApp);
                      
                }
    
                if (indappID != null)
                {
                    ViewData["IndAppID"] = indappID.Value;
                    //    viewModel.Enrollments = viewModel.Courses.Where(
                   // x => x.IndAppID == indappID).Single().Enrollments;
                }
    
    
                int pageSize = 10;
                return View(await PaginatedList<Application>.CreateAsync(Applications.AsNoTracking(), pageNumber ?? 1, pageSize));
            }
    
            // GET: Applications/Details/5
            public async Task<IActionResult> Details(int? id)
            {
                if (id == null)
                {
                    return NotFound();
                }
    
                var Application = await _context.Applications
                    .Include(a => a.AppAssignments)
                        .ThenInclude(e => e.IndApp)
                    .AsNoTracking()
                    .FirstOrDefaultAsync(m => m.ID == id);
    
                if (Application == null)
                {
                    return NotFound();
                }
    
                return View(Application);
            }
    
            // GET: Applications/Create
            public IActionResult Create()
            {
                return View();
            }
    
            // POST: Applications/Create
            // To protect from overposting attacks, please enable the specific properties you want to bind to, for
            // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
            [HttpPost]
            [ValidateAntiForgeryToken]
            public async Task<IActionResult> Create(
                [Bind("EnrollmentDate,BusinessUnit,FirstMidName,LastName,CTXApp")] Application application)
            {
                try
                {
                    if (ModelState.IsValid)
                    {
                        _context.Add(application);
                        await _context.SaveChangesAsync();
                        return RedirectToAction(nameof(Index));
                    }
                }
                catch (DbUpdateException /* ex */)
                {
                    //Log the error (uncomment ex variable name and write a log.
                    ModelState.AddModelError("", "Unable to save changes. " +
                        "Try again, and if the problem persists " +
                        "see your system administrator.");
                }
                return View(application);
            }
    
            // GET: Applications/Edit/5
            public async Task<IActionResult> Edit(int? id)
            {
                if (id == null)
                {
                    return NotFound();
                }
    
                var application = await _context.Applications.FindAsync(id);
    
                var instructor = await _context.Applications
                   // .Include(i => i.OfficeAssignment)
                   .Include(i => i.AppAssignments).ThenInclude(i => i.IndApp)
                    .AsNoTracking()
                    .FirstOrDefaultAsync(m => m.ID == id);
    
                if (application == null)
    
    
                {
                    return NotFound();
                }
                PopulateAssignedAppData(application);
                return View(application);
            }
    
            private void PopulateAssignedAppData(Application application)
            {
                var allindapps = _context.IndApps;
                var CTXAppsApps = new HashSet<int>(application.AppAssignments.Select(c => c.IndAppID));
                var viewModel = new List<AssignedIndAppData>();
                foreach (var indApp in allindapps)
                {
                    viewModel.Add(new AssignedIndAppData
                    {
                        IndAppID = indApp.ID,
                        AppName = indApp.Application    ,
                        Assigned = CTXAppsApps.Contains(indApp.ID)
                    });
                }
                ViewData["IndApps"] = viewModel;
            }
    
    
    
            // POST: Applications/Edit/5
            // To protect from overposting attacks, please enable the specific properties you want to bind to, for
            // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
            // [HttpPost, ActionName("Edit")]
            [HttpPost]
            [ValidateAntiForgeryToken]
            public async Task<IActionResult> Edit(int? id, string[] selectedIndApps)
            {
                if (id == null)
                {
                    return NotFound();
                }
    
                //var ApplicationToUpdate = await _context.Applications.FirstOrDefaultAsync(a => a.ID == id);
    
                var ApplicationToUpdate = await _context.Applications
                   //    .Include(i => i.OfficeAssignment)
                       .Include(i => i.AppAssignments)
                        .ThenInclude(i => i.IndApp)
                        .FirstOrDefaultAsync(m => m.ID == id);
    
    
    
                if (await TryUpdateModelAsync<Application>(
                    ApplicationToUpdate,
                    "",
                    a => a.BusinessUnit,a => a.FirstMidName, a => a.LastName, a => a.EnrollmentDate))
                {
    
                    UpdateApplicationIndApps(selectedIndApps, ApplicationToUpdate);
    
                    try
                    {
                        await _context.SaveChangesAsync();
                        return RedirectToAction(nameof(Index));
                    }
                    catch (DbUpdateException /* ex */)
                    {
                        //Log the error (uncomment ex variable name and write a log.)
                        ModelState.AddModelError("", "Unable to save changes. " +
                            "Try again, and if the problem persists, " +
                            "see your system administrator.");
                    }
                }
    
                UpdateApplicationIndApps(selectedIndApps, ApplicationToUpdate);
                PopulateAssignedAppData(ApplicationToUpdate);
    
                return View(ApplicationToUpdate);
            }
    
    
            private void UpdateApplicationIndApps(string[] selectedIndApps, Application ApplicationToUpdate)
            {
                if (selectedIndApps == null)
                {
                    ApplicationToUpdate.AppAssignments = new List<AppAssignment>();
                    return;
                }
    
                //var selectedIndAppsHS = new HashSet<string>(selectedIndApps);
                var selectedIndAppsHS = new HashSet<string>(selectedIndApps);
                var ApplicationIndApps = new HashSet<int>
                    (ApplicationToUpdate.AppAssignments.Select(c => c.IndApp.ID));
                foreach (var indapp in _context.Applications)
                {
                    if (selectedIndAppsHS.Contains(indapp.ID.ToString()))
                    {
                        if (!ApplicationIndApps.Contains(indapp.ID))
                        {
                            ApplicationToUpdate.AppAssignments.Add(new AppAssignment { ApplicationID = ApplicationToUpdate.ID, IndAppID = indapp.ID });
                        }
                    }
                    else
                    {
    
                        if (ApplicationIndApps.Contains(indapp.ID))
                        {
                            AppAssignment IndAppToRemove = ApplicationToUpdate.AppAssignments.FirstOrDefault(i => i.IndAppID == indapp.ID);
                            _context.Remove(IndAppToRemove);
                        }
                    }
                }
            }
    
    
    
    
    
    
    
    
    
    
    
            // GET: Applications/Delete/5
            public async Task<IActionResult> Delete(int? id, bool? saveChangesError = false)
            {
                if (id == null)
                {
                    return NotFound();
                }
    
                var Application = await _context.Applications
                    .AsNoTracking()
                    .FirstOrDefaultAsync(m => m.ID == id);
                if (Application == null)
                {
                    return NotFound();
                }
    
                if (saveChangesError.GetValueOrDefault())
                {
                    ViewData["ErrorMessage"] =
                        "Delete failed. Try again, and if the problem persists " +
                        "see your system administrator.";
                }
    
                return View(Application);
            }
    
            // POST: Applications/Delete/5
            [HttpPost, ActionName("Delete")]
            [ValidateAntiForgeryToken]
            public async Task<IActionResult> DeleteConfirmed(int id)
            {
                var application = await _context.Applications.FindAsync(id);
    
                if (application == null)
                {
                    return RedirectToAction(nameof(Index));
                }
    
                try
                {
    
                    _context.Applications.Remove(application);
                    await _context.SaveChangesAsync();
                    return RedirectToAction(nameof(Index));
                }
                catch (DbUpdateException /* ex */)
                {
                    //Log the error (uncomment ex variable name and write a log.)
                    return RedirectToAction(nameof(Delete), new { id = id, saveChangesError = true });
                }
            }
    
            private bool ApplicationExists(int id)
            {
                return _context.Applications.Any(e => e.ID == id);
            }
        }
    }
    
    Code:
    @model Tracker.Models.Application
    
    @{
        ViewData["Title"] = "Edit";
    }
    
    <h1>Edit</h1>
    
    <h4>Application</h4>
    <hr />
    <div class="row">
        <div class="col-md-4">
            <form asp-action="Edit">
                <div asp-validation-summary="ModelOnly" class="text-danger"></div>
                <input type="hidden" asp-for="ID" />
                <div class="form-group">
                    <label asp-for="CTXApp" class="control-label"></label>
                    <input asp-for="CTXApp" class="form-control" />
                    <span asp-validation-for="CTXApp" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <label asp-for="LastName" class="control-label"></label>
                    <input asp-for="LastName" class="form-control" />
                    <span asp-validation-for="LastName" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <label asp-for="FirstMidName" class="control-label"></label>
                    <input asp-for="FirstMidName" class="form-control" />
                    <span asp-validation-for="FirstMidName" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <label asp-for="BusinessUnit" class="control-label"></label>
                    <input asp-for="BusinessUnit" class="form-control" />
                    <span asp-validation-for="BusinessUnit" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <label asp-for="EnrollmentDate" class="control-label"></label>
                    <input asp-for="EnrollmentDate" class="form-control" />
                    <span asp-validation-for="EnrollmentDate" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <div class="col-md-offset-2 col-md-10">
                        <table>
                            <tr>
                                @{
                                    int cnt = 0;
                                    List<Tracker.Models.TrackerViewModels.AssignedIndAppData> indapps = ViewBag.Indapps;
    
                                    foreach (var indapp in indapps)
                                    {
                                        if (cnt++ % 3 == 0)
                                        {
                                        @:</tr><tr>
                                        }
                                        @:<td>
                                            <input type="checkbox"
                                                   name="selectedCourses"
                                                   value="@indapp.IndAppID"
                                                   @(Html.Raw(indapp.Assigned ? "checked=\"checked\"" : "")) />
                                            @indapp.IndAppID @:  @indapp.AppName
                                        @:</td>
                                    }
                                @:</tr>
                                }
                            </table>
                        </div>
                    </div>
                    <div class="form-group">
                        <input type="submit" value="Save" class="btn btn-primary" />
                    </div>
                </form>
        </div>
    </div>
    
    <div>
        <a asp-action="Index">Back to List</a>
    </div>
    
    @section Scripts {
        @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
    }
    
    Any pointers; much appreciated.
    Cheers, Paul.
     
  5. jsmoke

    Soldato

    Joined: Jun 17, 2012

    Posts: 6,986

    Your indappID is returning null meaning that there's no entry in the dB. Check the dB
     
  6. darkgen

    Wise Guy

    Joined: Mar 8, 2005

    Posts: 2,309

    Location: London, UK

    Hmm, theres def data there:

    Code:
    ApplicationID    IndAppID
    9    4
    9    5
    9    6
    10    5
    11    6
    12    6
    13    5
    14    6
    15    4
     
  7. jsmoke

    Soldato

    Joined: Jun 17, 2012

    Posts: 6,986

    Do you know how to debug, would be useful here?
     
  8. darkgen

    Wise Guy

    Joined: Mar 8, 2005

    Posts: 2,309

    Location: London, UK

    I'll play about it with it tomorrow! It's too good-a-day to stay indoors fumbling about with code :)
     
  9. Slinky69

    Associate

    Joined: Aug 19, 2016

    Posts: 42

    Location: Bristol

    The exception means that whatever you are calling Select() on is null. I believe you can prevent the exception by instead calling Collection?.Select() - The ?. operator will return null if the collection is null, rather than proceeding to call the Select() method.

    However that only stops the exception, doesn't really help with the underlying issue of why the collection is null ;)
     
  10. GeordieStew

    Associate

    Joined: Nov 3, 2014

    Posts: 95

    Could you use the new Live Share in VS2017/19 or VS Code? Sure someone could just jump in and help out that way.
     
  11. touch

    Capodecina

    Joined: Oct 28, 2006

    Posts: 10,993

    Location: Sufferlandria

    HashSet<int>(application.AppAssignments.Select(c => c.IndAppID));

    This line gets all of the AppAssignments which belong to application and then output the IndAppID value into your hashset.
    That's all going to work fine provided you have at least 1 AppAssignment or (as you've seen from the error you're getting) it's going to crash if there arn't any.
    The problem is that you're not just selecting all the AppAssignments from the AppAssignment table (you'd do _context.AppAssignments for that), you're using application.AppAssignments to get all the AppAssignments linked to the application object which you passed in. If the application object you've passed in didn't have any linked AppAssignments, that'll cause the error you're getting. Looking at the db table you posted earlier, applications with IDs between 1 and 8 don't have any linked AppAssignments
     
  12. darkgen

    Wise Guy

    Joined: Mar 8, 2005

    Posts: 2,309

    Location: London, UK

    Thank you all for the replies.
    I understand this simply masks the exception. I did look for examples for this but could not find the syntax Collection?.Select(), only collection_select().

    I'll have a look at thanks.
    OK this makes sense. However, in this instance and following on from the CU tutorial; I would of expected it would allow for instances where the Application may not be associated with any IndApp (individual application) and visa versa.

    I did recheck the table data and in this example the error still occurs when there is at least one IndApp associated with the Application.

    Code:
    ID    Application    Version
    4    Access    1
    5    Excel    2
    6    Word    3
    Code:
    ID    LastName    FirstName    BusinessUnit    EnrollmentDate    CTXApp
    9    Alexander    Carson    GMS    2005-09-01 00:00:00.0000000    FirstApp
    10    Alonso    Meredith    GMS    2002-09-01 00:00:00.0000000    GCMS
    11    Anand    Arturo    GMS    2003-09-01 00:00:00.0000000    Oracle
    12    Barzdukas    Gytis    GMS    2002-09-01 00:00:00.0000000    Empower
    13    Li    Yan    GMS    2002-09-01 00:00:00.0000000    TCSDesktop
    14    Justice    Peggy    VAX    2001-09-01 00:00:00.0000000    Documentum
    15    Norman    Laura    GMS    2003-09-01 00:00:00.0000000    OneCDS
    Code:
    ApplicationID    IndAppID
    9    4
    9    5
    9    6
    10    5
    11    6
    12    6
    13    5
    14    6
    15    4

    --
    EDIT. Removed the exception.

    var application = await _context.Applications.FindAsync(id);
    >
    var application = await _context.Applications

    Now on to the next challenge :) I am able to check and uncheck individual applications when editing the Applications but when saving it looks it does not make the insert/delete calls and just returns back to the Application list. No errors that I can see.
    Code:
            public async Task<IActionResult> Edit(int? id)
            {
                if (id == null)
                {
                    return NotFound();
                }
    
                //var application = await _context.Applications.FindAsync(id);
    
                var application = await _context.Applications
                   // .Include(i => i.OfficeAssignment)
                   .Include(i => i.AppAssignments).ThenInclude(i => i.IndApp)
                    .AsNoTracking()
                    .FirstOrDefaultAsync(m => m.ID == id);
    
                if (application == null)
    
    
                {
                    return NotFound();
                }
                PopulateAssignedAppData(application);
                return View(application);
            }
    
            private void PopulateAssignedAppData(Application application)
            {
                var allindapps = _context.IndApps;
                var CTXAppsApps = new HashSet<int>(application.AppAssignments.Select(c => c.IndAppID));
                var viewModel = new List<AssignedIndAppData>();
                foreach (var indApp in allindapps)
                {
                    viewModel.Add(new AssignedIndAppData
                    {
                        IndAppID = indApp.ID,
                        AppName = indApp.Application    ,
                        Assigned = CTXAppsApps.Contains(indApp.ID)
                    });
                }
                ViewData["IndApps"] = viewModel;
            }
    
    
    
            // POST: Applications/Edit/5
            // To protect from overposting attacks, please enable the specific properties you want to bind to, for
            // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
            // [HttpPost, ActionName("Edit")]
            [HttpPost]
            [ValidateAntiForgeryToken]
            public async Task<IActionResult> Edit(int? id, string[] selectedIndApps)
            {
                if (id == null)
                {
                    return NotFound();
                }
    
                //var ApplicationToUpdate = await _context.Applications.FirstOrDefaultAsync(a => a.ID == id);
    
                var ApplicationToUpdate = await _context.Applications
                        .Include(i => i.AppAssignments)
                        .ThenInclude(i => i.IndApp)
                        .FirstOrDefaultAsync(m => m.ID == id);
    
                if (await TryUpdateModelAsync<Application>(
                    ApplicationToUpdate,
                    "",
                    i => i.CTXApp, i => i.BusinessUnit,i => i.FirstMidName, i => i.LastName, i => i.EnrollmentDate))
                {
                    UpdateApplicationIndApps(selectedIndApps, ApplicationToUpdate);
                    try
                    {
                        await _context.SaveChangesAsync();
                      
                    }
                    catch (DbUpdateException /* ex */)
                    {
                        //Log the error (uncomment ex variable name and write a log.)
                        ModelState.AddModelError("", "Unable to save changes. " +
                            "Try again, and if the problem persists, " +
                            "see your system administrator.");
                    }
                    return RedirectToAction(nameof(Index));
                }
    
                UpdateApplicationIndApps(selectedIndApps, ApplicationToUpdate);
                PopulateAssignedAppData(ApplicationToUpdate);
                return View(ApplicationToUpdate);
            }
    
    
            private void UpdateApplicationIndApps(string[] selectedIndApps, Application ApplicationToUpdate)
            {
                if (selectedIndApps == null)
                {
                    ApplicationToUpdate.AppAssignments = new List<AppAssignment>();
                    return;
                }
    
                var selectedIndAppsHS = new HashSet<string>(selectedIndApps);
                var ApplicationIndApps = new HashSet<int>
                    (ApplicationToUpdate.AppAssignments.Select(c => c.IndApp.ID));
                foreach (var indapp in _context.Applications)
                {
                    if (selectedIndAppsHS.Contains(indapp.ID.ToString()))
                    {
                        if (!ApplicationIndApps.Contains(indapp.ID))
                        {
                            ApplicationToUpdate.AppAssignments.Add(new AppAssignment { ApplicationID = ApplicationToUpdate.ID, IndAppID = indapp.ID });
                        }
                    }
                    else
                    {
    
                        if (ApplicationIndApps.Contains(indapp.ID))
                        {
                            AppAssignment IndAppToRemove = ApplicationToUpdate.AppAssignments.FirstOrDefault(i => i.IndAppID == indapp.ID);
                            _context.Remove(IndAppToRemove);
                        }
                    }
                }
            }


    ---
    Second issue relates to use paginated lists. index.cshtml is throwing an error suggesting missing directive or Assembly reference.

    Throwing the error at lines;
    @foreach (var item in Model.Applications)

    @if (Model.IndApps != null)

    @foreach (var item in Model.IndApps)

    Yet; These are included in the referenced class on the first line of the index.cshtml
    @model PaginatedList<Tracker.Models.TrackerViewModels.ApplicationIndexData>
    Code:
    @model PaginatedList<Tracker.Models.TrackerViewModels.ApplicationIndexData>
    
    
    @{
        ViewData["Title"] = "Citrix Applicatiom";
    }
    
    <h1>Index</h1>
    
    <p>
        <a asp-action="Create">Create New</a>
    </p>
    
    <form asp-action="Index" method="get">
        <div class="form-actions no-color">
            <p>
                Find by name: <input type="text" name="SearchString" value="@ViewData[" currentFilter"]" />
                <input type="submit" value="Search" class="btn btn-default" /> |
                <a asp-action="Index">Back to Full List</a>
            </p>
        </div>
    </form>
    
    <table class="table">
        <thead>
            <tr>
                <th>
                    <a asp-action="Index" asp-route-sortOrder="@ViewData["NameSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">CTXApp</a>
                </th>
                <th>
                    <a asp-action="Index" asp-route-sortOrder="@ViewData["NameSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">Last Name</a>
                </th>
                <th>
                    First Name
                </th>
                <th>
                    Business Unit
                </th>
                <th>
                    <a asp-action="Index" asp-route-sortOrder="@ViewData[" DateSortParm"]" asp-route-currentFilter="@ViewData[" CurrentFilter"]">Enrollment Date</a>
                </th>
                <th>
                    Application
                </th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            @foreach (var item in Model.Applications)
            {
                string selectedRow = "";
                if (item.ID == (int?)ViewData["ApplicationID"])
                {
                    selectedRow = "success";
                }
                <tr class="@selectedRow">
                    <td>
                        @Html.DisplayFor(modelItem => item.CTXApp)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.LastName)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.FirstMidName)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.BusinessUnit)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.EnrollmentDate)
                    </td>
                    <td>
                        @{
                            foreach (var indapp in item.AppAssignments)
                            {
                                @indapp.IndApp.ID @:  @indapp.IndApp.Application <br />
                            }
                        }
                    </td>
                    <td>
                        <a asp-action="Index" asp-route-id="@item.ID">Select</a> |
                        <a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
                        <a asp-action="Details" asp-route-id="@item.ID">Details</a> |
                        <a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
                    </td>
                </tr>
            }
        </tbody>
    </table>
    
    
    @if (Model.IndApps != null)
    {
        <h3>Applications presented to solution.</h3>
        <table class="table">
            <tr>
                <th></th>
                <th>ID</th>
                <th>Application</th>
                <th>Version</th>
            </tr>
    
            @foreach (var item in Model.IndApps)
            {
                string selectedRow = "";
                if (item.ID == (int?)ViewData["CourseID"])
                {
                    selectedRow = "success";
                }
                <tr class="@selectedRow">
                    <td>
                        @Html.ActionLink("Select", "Index", new { indappID = item.ID })
                    </td>
                    <td>
                        @item.ID
                    </td>
                    <td>
                        @item.Application
                    </td>
                    <td>
                        @item.Version
                    </td>
                </tr>
            }
    
        </table>
    }
    
        @{
            var prevDisabled = !Model.HasPreviousPage ? "disabled" : "";
            var nextDisabled = !Model.HasNextPage ? "disabled" : "";
        }
    
        <a asp-action="Index"
           asp-route-sortOrder="@ViewData[" CurrentSort"]"
           asp-route-pageNumber="@(Model.PageIndex - 1)"
           asp-route-currentFilter="@ViewData[" CurrentFilter"]"
           class="btn btn-default @prevDisabled">
            Previous
        </a>
        <a asp-action="Index"
           asp-route-sortOrder="@ViewData[" CurrentSort"]"
           asp-route-pageNumber="@(Model.PageIndex + 1)"
           asp-route-currentFilter="@ViewData[" CurrentFilter"]"
           class="btn btn-default @nextDisabled">
            Next
        </a>
    Code:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace Tracker.Models.TrackerViewModels
    {
        public class ApplicationIndexData
        {
            public IEnumerable<Application> Applications { get; set; }
            public IEnumerable<IndApp> IndApps { get; set; }
        }
    }
    
     
    Last edited: Apr 20, 2019