How is the query generated in Linq mounted when we do UPDATE?

Asked

Viewed 687 times

6

How the query generated in Linq is mounted when we do UPDATE?

using ColWebDBContext.DBase.Banco;
using System;
using System.Web.UI;
using System.Linq;

namespace DBContext
{
    public partial class _Default : Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            using (var ctx = new dbContext())
            {
                var Produto = ctx.Tabela_Produtos.FirstOrDefault(p => p.Produto == 1);
                Produto.Nome = "Bombril";
                ctx.SaveChanges();
            }
        }
    }
}

In the example above, I search all object columns (Table_products), change the field Name and send the Context save, if I were doing the update query with the sql syntax that would be like this;

update Tabela_Produtos
set Nome = 'Bombril'
where Produto = 1;

My doubts are;

  1. The Context has some form to generate the same syntax?
  2. Is there any way to see the query being sent to bank in that case?

The question below is the most critical and the one I’m most interested in knowing.

  1. As it is done by Context so that he knows that only the column Name has changed?
  • Question 2 complements Question 1, certain?

  • I practically just need to know how to see this query, some way to capture it. There’s not a lot of relation between 1 and 2. The first I want to know how it’s generated and the second I want to know if there’s any way I can capture it, copy it. understanding this process will help me solve this other

  • You are using SQL Server?

  • @Randrade, exactly, I don’t know if there’s any difference between banks.

  • 1

    has tools that SQL has exactly to help with that. I’ll be working out a more detailed answer here.

  • @Randrade, but is this through the bank? because the 2 question may be, but 1 and 3 would like to know the (properties , methods ) used by Context,

  • That question is not duplicated of this?

  • @jbueno, no... has the same goal, but and another thing , I spoke here

  • What a mess...

  • @jbueno, why ? is not clear the question? if I edited the other with that the more would become very large.

  • @jbueno, what I thought to solve the other case was the following, if I knew how it is done in the context for it to only change a certain field then have the possibility of I tell which fields I want to change with that I could select only from the fields I want and say which ones I want to change.

Show 6 more comments

2 answers

5

  1. The Context has some form to generate the same syntax?

I don’t know, but I don’t think... the use of entity when you want to do "things" of ADO.NET.

  1. Is there any way to see the query being sent to the bank in this case?

Yes. You can create your own logger or create a simple extension:

public static class QueryHelper
{
    public static string TraceSql<T>(this IQueryable<T> t)
    {
        var sql = "";
        ObjectQuery<T> oqt = t as ObjectQuery<T>;

        if (oqt != null)
            sql = oqt.ToTraceString();

        return sql;
    }
}

Or:

ctx.Database.Log = x => System.Diagnostics.Debug.WriteLine(x);
  1. As it is done by Context so that he knows that only the column Name has changed?

Through the Getmodifiedmembers or through a small implementation:

using (var ctx = new dbContext())
{
    var Produto = (from p in ctx.Produto
                            where p.Produto == 1
                            select p).FirstOrDefault();
    Produto.Nome = "Bombril";

    QueryHelper<Product>.Log(db, Produto);//seu logger

    ctx.SaveChanges();
}


public static class QueryHelper
{
    public static void Log<T>(DataContext dataContext, T entidade) where T : Class
    {
        foreach(var propriedadeModificada in dataContext.GetTable<T>().GetModifiedMembers(entidade))
        {
            var valorAtual = propriedadeModificada.CurrentValue;
            var valorOriginal = propriedadeModificada.OriginalValue;
        }
    }
}
  • in 2, what would I call this method? through the Product.Tracesql(); ?

  • Exactly, @Gokussjgod.

  • but it would not return me the query of my select ?

  • I tried here not to work calling this way, the Product is already a materialized object with the (Firstordefault). there is no way to pass it as Iqueryable.

  • I also don’t have the method or class (Gettable) in my dbContext. that’s from some external library ?

  • edited the answer with other information and adjustments.

  • Note that Product is already a materialized object, then the flame ctx.Produt.Getmodifiedmembers(Product); the part ctx. Product , will not exist and also could not call through ctx.Tabela_products.Getmodifiedmembers(Product); it returns me error CS1106 C# Extension method must be defined in a non-generic Static class

  • 1

    GetModifiedMembers http://stackoverflow.com/questions/11412116/linq-to-sql-logging-with-getmodifiedmembers-lookup-values is for the old layer Linq To SQL and what was asked is Entity Framework as far as I could make out!

  • 1

    the implementation principle is the same @Virgilionovic. I edited the response with another approach using the GetModifiedMembers.

  • @Marllonnasser, question 1, actually it does have a way of knowing what was changed and based on that context and smart enough to generate the simplified query with exactly the fields that were changed. saw this in the book Entity Framework 4 the structure of entities in action page 82.

  • You say the question #3, @Gokussjgod? #1 is about creating statements "in hand" with the Context, that’s not it?

Show 6 more comments

3


As the context (DbContext) works when I call an entity by First(), FirstOrDefault(), Find(value), that is, I bring a record for change:

Model:

[Table("Credit")]
public class Credit
{
    public Credit()
    {
    }
    public Credit(string description)
    {
        Description = description;
    }
    public Credit(int id, string description)
    {
        Id = id;
        Description = description;
    }

    [Key()]  
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]        
    public int Id { get; set; }

    [Required()]
    [MaxLength(50)]
    public string Description { get; set; }

    public bool Status { get; set; }
    public int Lines { get; set; }
}

Context ():

public class Database  : DbContext
{
    public Database()
        :base(@"Server=.\SqlExpress;Database=dbtest;User Id=sa;Password=senha;")
    {
       Database.Initialize(false);
    }

    public DbSet<Credit> Credit { get; set; }    
}

Running operations:

class Program
{
    static void Main(string[] args)
    {
        using (Database db = new Database())
        {
            db.Database.Log = ca => WriteLog(ca);

            int value = 1;
            Credit cr = db.Credit.Find(value);
            cr.Lines = cr.Lines + 1;
            db.SaveChanges();

        }



        System.Console.WriteLine("Pression <Enter> ...");
    }

    public static void WriteLog(string c)
    {
        System.Console.WriteLine(c);
    }
}

In the above code is used the basic audit which shows which SQL are being generated, in the case example are two a Select and a Update, being an update only of what has been modified, as demonstrated in debug just below:

inserir a descrição da imagem aqui

Then conclude that the update only the property that has been changed.

1 - Context has some form to generate the same syntax?

Yes it generates the same syntax, updating only the properties that have been changed.

2 - Is there any way to see the query that is being sent to the bank in this case?

Yes exite, db.Database.Log will bring the SQL generated by context.

using (Database db = new Database())
{
     db.Database.Log = ca => WriteLog(ca);

Can also be used in the Debug Trace:

db.Database.Log = ca => System.Diagnostics.Debug.WriteLine(ca);

inserir a descrição da imagem aqui


3 - How is done by Context to let it know that only the column Name has changed?

Credit cr = db.Credit.Find(value);
cr.Lines = cr.Lines + 1;
db.Entry(cr).Property(x => x.Lines).IsModified

This shows db.Entry(cr).Property(x => x.Lines).IsModified if the property has undergone any alteration, the Context is based on the truth answer (true) and the code is responsible for changing only what is modified as true.

There is nothing implemented to check which fields are modified at once, but it can be done easily by an extension method to tell which fields have changed and which have not suffered:

public static class MethodsUpdate
{
    public static Dictionary<string, bool> GetUpdatePropertyNames<T>(this DbEntityEntry<T> entry)
        where T: class, new()
    {
        Dictionary<string, bool> entryUpdate =
            new Dictionary<string, bool>();
        foreach (string name in entry.CurrentValues.PropertyNames)
        {
            entryUpdate.Add(name, entry.Property(name).IsModified);
        }
        return entryUpdate;
    }
}

Dictionary<string, bool> propertyChanges = db.Entry(cr).GetUpdatePropertyNames();

inserir a descrição da imagem aqui

In this specific case the change in the bank has not yet been applied, only in its context.

References:

  • I think the method WriteLog will only work in ConsoleApplications, nay?

  • 1

    @Marllonnasser, in this example yes, but the need is really testing, but, you can use anywhere generating logs and this is very useful, not limited only in Console Application. This can be used in various ways !!!

  • 1

    Consoleapplications is not a problem for me.

  • Don’t I understand @Gokussjgod? Sorry!

  • 2

    He meant that he can use the proposed solution, even if it is "only" in ConsoleApplication. I thought your application was web, @Gokussjgod.

  • 1

    About the above, Consoleapplications is no problem, it just has no explanation for number 3. my application is web yes... but I can change it to an application text field.

  • 1

    Opa @Gokussjgod I’m already posting !!!

  • 1

    @Gokussjgod I made an issue I hope to have helped.

  • is not well explained, but the past functions served the purpose.

  • What can I improve @Gokussjgod please can say?

  • 1

    beautiful implementation of GetUpdatePropertyNames!! +1

  • Vlw @Marllonnasser

  • @Gokussjgod if I can improve more, with some tip from you, the other doubt, you can say without problems, and I stand by, I’ll go out on the way back if I can help.

  • 1

    A few references would be great.

Show 9 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.