-1

Suppose that I have a class name User, is there any ways to populate the class properties and default value in Visual Studio as follow. I feel it is tedious to repeat typing the properties again and again.

Probably there is default shortcut to do this in Visual Studio or any extension that can do this?

Case 1

var user = db.User.Where(x => x.UserID).Select(o => new User
{
   UserId = o.UserId, // auto populate
   Username = o.Username, // auto populate
   ........  // auto populate all properties inside User class
}
);

case 2

var user = new User();
user.UserID = "",  // auto populate with type default value
user.Username = "",  // auto populate with type default value
........ // auto populate all properties inside User class
........ // auto populate all properties inside User class
eulercode
  • 1,107
  • 4
  • 16
  • 29
  • 2
    What's wrong with setting their default value in the default constructor? – Martheen Apr 05 '21 at 05:44
  • `new User();` will populate the properties with the type's default value already. Note that `""` is _not_ the default value of a `string`. A `string` is a reference type, so its default value is `null`. – ProgrammingLlama Apr 05 '21 at 05:47
  • As for case 1, just drop the entire .Select and you'll get the enumerable of Users, or create a dedicated Clone() if you want to duplicate them instead. – Martheen Apr 05 '21 at 05:47
  • @Martheen for case 1 sometimes the User class does not map to db.User (eg, i might need an additional field to User class on top of properties value return in db.User, eg: age which is not return from the database) where in such cases i need to retype the property 1 by 1 again. What do you mean by dedicated clone and how that could be done – eulercode Apr 05 '21 at 05:49
  • The expression doesn't have to be a single statement. Select(o=> { var d = o.Clone(); d.NewProperty = newValue; return d;} works. – Martheen Apr 05 '21 at 05:53
  • A dedicated clone is just that. User Clone() => return new User {UserId=this.UserID; ...} – Martheen Apr 05 '21 at 05:55
  • For case 1, perhaps a library such as AutoMapper might be what you want? You could then do something like `var users = _mapper.Map>(db.user.Where(query));`. For case 2, why not just set the default when you define the property? For example: `public string Username {get;set;} = "Bob";`, and then if you don't assign a value to it it will be "Bob". – ProgrammingLlama Apr 05 '21 at 05:55
  • @Llama yes for case 1 probably i think i can use automapper – eulercode Apr 05 '21 at 05:56
  • @Martheen Clone() is not a function is that any library that I need to import? – eulercode Apr 05 '21 at 05:57
  • Either write it yourself, or if both the User from DB and the User you want is the same class, use https://learn.microsoft.com/en-us/dotnet/api/system.object.memberwiseclone?view=net-5.0 – Martheen Apr 05 '21 at 05:58
  • @Martheen the solution u proposed for case 1 does not work i got error `A lambda expression with a statement body cannot be converted to an expression tree`. Seems that it cannot be used for linq to sql context https://stackoverflow.com/questions/5179341/a-lambda-expression-with-a-statement-body-cannot-be-converted-to-an-expression It is AsEnumerable() and i do not want it to change it to ToList() before select as it will impact performance (as i need to do pagination). cannot afford to query whole list from database. – eulercode Apr 05 '21 at 06:04
  • 1
    This sounds like something that "automapper" would happily do for you – Marc Gravell Apr 05 '21 at 06:09
  • @MarcGravell AutoMapper does not work for case 1, at least not in AsQueryable() – eulercode Apr 05 '21 at 06:14
  • 1
    @eulercode Do the [Queryable Extensions](https://docs.automapper.org/en/stable/Queryable-Extensions.html) help? – ProgrammingLlama Apr 05 '21 at 06:16
  • @Llama cool i will look at the queryable extensions – eulercode Apr 05 '21 at 06:19

2 Answers2

0

I'm not quite sure what are you trying to achieve here

var user = db.User.Where(x => x.UserID).Select(o => new User
{
  UserId = o.UserId, // auto populate
  Username = o.Username, // auto populate
  ........  // auto populate all properties inside User class
}

since both new User and db.User are the same type of class/entity. But let's say you have an entity model User and a DTO/View model called UserViewModel and you want automatically to map the values of User to UserViewModel you can use automapper https://docs.automapper.org/en/stable/Getting-started.html Example this is the Entity definition

public class User 
{
   public int Id {get; set;}
  
   public string FirstName {get; set;}

   public string LastName {get; set;}
 
   public int Age {get; set;}
}

And we have a UserViewModel to which you want to map the data from User

  public class UserViewModel 
  {
     public int Id {get; set;}
  
     public string FirstName {get; set;}

     public string LastName {get; set;}
 
     public int Age {get; set;}
   }

With AutoMapper you can do this

 var configuration = new MapperConfiguration(config =>
 {
     config.CreateMap<User, UserViewModel>();
 }

and then you can use the mapper configuration like this

var user = db.User.Where(x => x.UserID).First();
var userViewModel = configuration.CreateMapper().Map<UserViewModel>(user);

This will automatically populate the property values of User to UserViewModel. Alternatively you can have a view model like this

public class UserViewModel 
{
     public int Id {get; set;}
  
     public string FullName {get; set;}
 
     public int Age {get; set;}
}

This time not all properties of User and UserViewModel match one to one and you will have to set a custom mapper configuration i.e.

var configuration = new MapperConfiguration(config =>
 {
     config.CreateMap<User, UserViewModel>()
           .ForMember(uvm => uvm.FullName, o => o.MapFrom($"{u.FirstName} {u.LastName}") );
 }

This way you are configuring the automatic User to UserViewModel mapping to map the FullName property value by concatenating FirstName and LastName from User

Anton Kovachev
  • 322
  • 3
  • 6
0

Well I have build a library that could solve this problem for you, called FastDeepCloner

   public class User 
    {

        public virtual string Name { get; set; } = "sdjh";

        public virtual int PasswordLength { get; set; } = 6;

        public Circular Test { get; set; } = new Circular();

    }
    
    public class CloneToTest
    {
        [FastDeepCloner.FastDeepClonerColumn("Name")] 
        [FastDeepCloner.FastDeepClonerColumn("LastName")] // Or
        public string FullName { get; set; }
        
        // You see here the type could be difrrent then the orginal type. 
        // FastDeepCloner will try to convert it, if it fail then a default value will be inserted insted
        public string PasswordLength { get; set; }
        
        // You could add a path insted, remember this only work on none list items.
        [FastDeepClonerColumn("Test.myBar.Id")]
        public int Id { get; set; }

        public Circular Test { get; set; }
    }

Now simple use

  var user = new User() { Name = "alen toma" };
        var cloneTo =new  CloneToTest();

        FastDeepCloner.DeepCloner.CloneTo(user, cloneTo);
  
        Assert.AreEqual(user.Name, cloneTo.FullName);
Alen.Toma
  • 4,684
  • 2
  • 14
  • 31