简体   繁体   中英

C# build taking a very long time because of large array of data

I have a solution that has three projects. One of those projects takes a very long time to build and I have narrowed it down to initialisation data and in particular a very large array of suburb objects.

Below is the APISuburbInitialiser class but in particular the array of suburbs - this is the issue:

using JobsLedger.API.InitalisationData.Interfaces;
using JobsLedger.DATA;
using JobsLedger.DATA.Entities;
using System.Linq;

namespace JobsLedger.API.InitalisationData {
    public class APISuburbInitialiser : IAPISuburbInitialiser {
        public void InitialiseStaInitialiseStatesAndSuburbs(APIDbContext context) {
            InitialiseStates(context);
            InitialiseSuburbs(context);
        }

        private void InitialiseStates(APIDbContext context) {
            // Look for any students.
            if (context.States.Any()) {
                return; //DB table data already created.
            }

            var states = new State[]
            {
                new State { StateName = "New South Wales", StateShortName = "NSW" },
                new State { StateName = "Victoria", StateShortName = "VIC" },
                new State { StateName = "Queensland", StateShortName = "QLD" },
                new State { StateName = "South Australia", StateShortName = "SA" },
                new State { StateName = "Western Australia", StateShortName = "WA" },
                new State { StateName = "Tasmania", StateShortName = "TAS" },
                new State { StateName = "Nothern Territory", StateShortName = "NT" },
                new State { StateName = "Australian Captial Territory", StateShortName = "ACT" }
            };

            foreach (State s in states) {
                context.States.Add(s);
            }

            context.SaveChanges();
        }

        private void InitialiseSuburbs(APIDbContext context) {

            // Look for any suburbs.
            if (context.Suburbs.Any()) {
                return; //DB table data already created.
            }

            // Upgraded due to database arbritarily assigning Id keys to  states in different order.
            var stateID = context.States.FirstOrDefault(s => s.StateShortName == "ACT").Id;

            var suburbs = new Suburb[] {
                new Suburb { PostCode = "200", SuburbName = "Australian National University", StateId = stateID, Latitude = -35.2777, Longditude = 149.1189 },
                new Suburb { PostCode = "221", SuburbName = "Barton", StateId = stateID, Latitude = -35.3049, Longditude = 149.14124 },
                new Suburb { PostCode = "2540", SuburbName = "Hmas Creswell", StateId = stateID, Latitude = -35.028, Longditude = 150.55013 },
                new Suburb { PostCode = "2540", SuburbName = "Jervis Bay", StateId = stateID, Latitude = -35.028, Longditude = 150.55014 },
                new Suburb { PostCode = "2540", SuburbName = "Wreck Bay", StateId = stateID, Latitude = -35.0169, Longditude = 150.63193 },
                new Suburb { PostCode = "2600", SuburbName = "Duntroon", StateId = stateID, Latitude = -35.3, Longditude = 149.16674 },
                new Suburb { PostCode = "2600", SuburbName = "Russell", StateId = stateID, Latitude = -35.2977, Longditude = 149.1514 },
                new Suburb { PostCode = "2600", SuburbName = "Harman", StateId = stateID, Latitude = -35.3053, Longditude = 149.13654 },
                new Suburb { PostCode = "2600", SuburbName = "Hmas Harman", StateId = stateID, Latitude = -35.31, Longditude = 149.13853 },
                new Suburb { PostCode = "2600", SuburbName = "Deakin", StateId = stateID, Latitude = -35.3193, Longditude = 149.10314 },
                new Suburb { PostCode = "2600", SuburbName = "Parliament House", StateId = stateID, Latitude = -35.3126, Longditude = 149.12783 },
                new Suburb { PostCode = "2600", SuburbName = "Yarralumla", StateId = stateID, Latitude = -35.2998, Longditude = 149.10584 },
                    ...

Suburb is as follows:

using JobsLedger.CATALOG.Entities.Interfaces;
using System.Collections.Generic;

namespace JobsLedger.CATALOG.Entities
{
    public class Suburb : IEntityBase
    {
        public Suburb()
        {
            Tenants = new List<Tenant>();
            Users = new List<User>();
        }

        public int Id { get; set; }
        public string SuburbName { get; set; }
        public string PostCode { get; set; }

        public double Latitude { get; set; }
        public double Longditude { get; set; }

        // One state to many suburbs
        public int StateId { get;  set; }
        public State State { get; set; }


        public virtual ICollection<Tenant> Tenants { get; set; }
        public virtual ICollection<User> Users { get; set; }
    }
}

There are 16000 odd suburbs and I use this array to populate a table in the database with all the suburbs.

What I have just found is that this array of suburbs (and also 1000 clients in another initialisation class) is causing the build for this project to take ages - minutes in fact. Take these classes out and the build takes next to no time.

Is there a way to have this in the project (or a way to load this data another way at run time) so as not to cause the build to take minutes..

UPDATE

I chose to create initially two new projects - one for Initialisations (used by all databases - its a tenanted system) and one for testdata - for only one database. I Then further created another project for authorisation. This way I could carve off those parts of the code that were being accessed by all other projects (or a number of them) and they stay stagnant requiring one build. Doing this really helped my understanding as to which way the dependencies worked between my projects.

  • Move the suburb init into another project. This will then be compiled once but not each time you change something to your other project.
  • Or move the postcode/name information to a resource file. Read it in at start-up time, this should make it faster to build.

This is a great use case for data seeding.

You could make a static class:

public static class Seeds
{
    public static IEnumerable<State> States = new State[]
    {
        new State { StateName = "New South Wales", StateShortName = "NSW" },
        ⋮
    }

    public static IEnumerable<Suburb> Suburbs = new Suburb[]
    {
        new Suburb { PostCode = "200", SuburbName = "Australian National University", StateId = stateID, Latitude = -35.2777, Longditude = 149.1189 },
        ⋮
    }
}

Then if you can have it added to your migration:

public class APIDbContext : DbContext
{
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        ⋮
        modelBuilder.Entity<State>().HasData(Seeds.States);
        modelBuilder.Entity<Suburb>().HasData(Seeds.Suburbs);
    }
}

Here, you can hardcode whatever Ids you need in your Seeds class. As long as you never change those Ids, your seed data will persist through all migrations.

This type of seed data is managed by migrations and the script to update the data that's already in the database needs to be generated without connecting to the database. This imposes some restrictions:

  • The primary key value needs to be specified even if it's usually generated by the database. It will be used to detect data changes between migrations.
  • Previously seeded data will be removed if the primary key is changed in any way.

Therefore this feature is most useful for static data that's not expected to change outside of migrations and does not depend on anything else in the database, for example ZIP codes.

Reference: Data Seeding

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM