|
I should clarify that the newer ways of working with threads the .NET have introduced, such as Background Worker threads, PLINQ, etc, ensure that there is less expected of the developer, so using these new options appear to be far more controlled, so I should have made that more clear up front.
When to use threads and when not to as highlighted in www.albahari.com/threading is something I will be following in future.
My concern is around the use of allowing someone to spawn new Threads everywhere without something to check what he is doing and identify how bad it gets very quickly! Add in a mix of synchronisation, but also mis-applied, with extra dependancies to other classes and extra sleep delays to compensate for being completely in the fog, and it produces the perfect application where defects lurk in ever corner, but don't get detected until run in live production a million times over!
|
|
|
|
|
I think you're blowing this WAY out of proportion.
You make is sound as though you're walking through a dense minefield every time you think of launching a new thread. That's just not the case. If you understand how to do threading properly and take the proper precautions around making sure that shared access is properly maintained, you'll never have a problem. All of the horror stories you here over this are because things were not done properly or something was missed along the way and an avenue of potential failure was left in the code.
With proper planning and thorough investigation, this isn't a problem. There are thousands of multi-threaded apps in production that never have an issue. So what are you worried about?? The only thing that's scaring you is that you haven't done it yourself and your skill set doesn't include the knowledge of how to manage proper threading.
|
|
|
|
|
I fully recognise there are whole teams of developers out there that can design flawless designs knowing they need to keep it simple. Equally, I recognise that there are plenty of other simpler options for most cases that you practically roll out the box. That is fine and I recognise that I will be getting responses from developers who do know way more than me on this. Fine.
What about when you come across an over complex design that you know to be flawed where clearly the designer didnt realise that it is a seriously bad idea to just spawn threads everywhere? Are you so sure that you want to turn a blind eye just because the compiler doesnt throw any errors and all your error handling reports nothing? How confident would you be over your data? Can you trust that some other junior doesnt come alone and unknowingly just add some static data? And that no matter how many times you point out how fundamentally flawed a design is to a manager, since there is no evidence of an error, there is no error?
Am i making any sense?
|
|
|
|
|
I don't think it's a matter of "turning a blind eye" to potential problems. This is where proper mentoring and supervision come in, along with design reviews, code reviews, checkin buddies, unit tests, continuous integration etc. etc. In fact, with modern approaches to design and development, it's a lot easier to produce reliable multi-threaded systems than it was say 20 or 30 years ago.
To use a simile, it's like building a suspension bridge - you make sure the designs are checked and re-checked, and that calculations and simulations run multiple times. Or, if you want to compare the lone developer mode, if you're building a garden shed, you'll make sure it's put together properly, step by step.
Like it or not multi-threading is here to stay[1] and it really is the only way to build properly interactive and/or networked applications. The project (very large project) I'm on at the moment is making extensive use of threading and we very seldom have any problems due to it - mostly problems arise within threads. Getting it right is a matter of good design and good control over how the system is put together.
In fact, nearly everything I've worked on over the years has been multi-threaded / parallel-processing, and I reckon, as with the current job, inter-process problems have been in a very small minority.
OK, threading can bite you unexpectedly, but just remember "let's be careful out there"...
[1] "here to stay" - was it ever away? Multi-threading has been around since pretty much the beginning of computing, and even interrupt servicing could be thought of as a separate thread.
There are three kinds of people in the world - those who can count and those who can't...
|
|
|
|
|
I follow everything everyone keeps highlighting about how this has been around for years and is used everywhere.
I just wish this had all come with a health warning, because, no matter how many people tell me they've used it for years, I have come across people who unfortunately still under the illusion that multi-threading is the silver bullet to increase performance (talking single core here as this is what they've always believed.) Never mind that a clumsy design includes enough delays to probably falsify any such suggestion anyway! If someone's understanding of OO re-useability stopped at inheritance, how much are they going to know about design patterns and anything sensible about multi-threading? Some companies are run by managers not developers (if you know what i mean), which I think is unfortunate and a bit scary given the tools that are used without thought...
|
|
|
|
|
Justin Fox wrote: no matter how many people tell me they've used it for years, I have come across people who unfortunately still under the illusion that multi-threading is the silver bullet to increase performance
You just said it yourself, though the words are slightly out of order. Multi-threading gives the illusion of increased performance.
Justin Fox wrote: Never mind that a clumsy design includes enough delays to probably falsify any such suggestion anyway! If someone's understanding of OO re-useability stopped at inheritance, how much are they going to know about design patterns and anything sensible about multi-threading? Some companies are run by managers not developers (if you know what i mean), which I think is unfortunate and a bit scary given the tools that are used without thought...
OK, so what's the whole point of all this?? Scared of a bunch of idiot developers and the crap you may get stuck supporting??
|
|
|
|
|
Justin Fox wrote: I fully recognise there are whole teams of developers out there that can design flawless designs knowing they need to keep it simple. Equally, I recognise that there are plenty of other simpler options for most cases that you practically roll out the box. That is fine and I recognise that I will be getting responses from developers who do know way more than me on this. Fine.
Guy, I've done dozens of times without running into any issues like you're describing. And I'm a team of 1. Noone checks my work over but me.
Justin Fox wrote: What about when you come across an over complex design that you know to be flawed where clearly the designer didnt realise that it is a seriously bad idea to just spawn threads everywhere?
Scrap it and rewrite it properly. Don't try and give me that argument that it "costs too much." It costs WAY more to do it badly and have to support it then it does to scrap it and redo it from scratch.
This is also where teams of people come into play checking each others works and designs. If you don't have a threading expert sitting around your shop, hire a consultant to check over the work.
Justin Fox wrote: Can you trust that some other junior doesnt come alone and unknowingly just add some static data?
I don't trust anyone. Even the guy I sit next to every single day.
Justin Fox wrote: And that no matter how many times you point out how fundamentally flawed a design is to a manager, since there is no evidence of an error, there is no error?
At that point, the accountibility stands with the manager, not the putz who wrote the code. If the manager want to release sub-par quality like that, well you're just going to have to stand up for yourself.
|
|
|
|
|
You talk of this as if it is something new. Almost every OS since the dawn of time has relied on multi-threading just to run the simplest systems. I wrote my first multi-threaded program in about 1969! I think Eddy made the point earlier that all you need to do is stick to the simple rules:
1. If an object is shared across threads then it must be locked and unlocked as appropriate.
2. If you don't understand threading then don't use it.
|
|
|
|
|
Agreed on your 2 points, and I feel confident in a clean and simple design this is straight forward.
Ever come across a design involving one thread calling into a class that itself calls back - cyclic redundancy that i spotted on day 1. Manual reset signalling on both sides, waithandles, and quite a few other dependancies that at a high level are immediately identified as making it unstable. Feels like this would just chase its tail and make one dizzy - hard to spot the intent of the design except to say its clumzy and most likely flawed, but lots of work to do if one actually needed to dead certain it was not going to bite you in your sleep!
I think you would be amazed who is sometimes given the firecrackers to play with!
Constructively, is there any simple technique for testing or verifying correctness of design?
|
|
|
|
|
Ok, ok.
I retract my assertion in its current form.
I really didn't expect developers to be so complacent about this given what I have seen, but that probably explains the difference in the type of places we work.
I think the only thing I've managed to prove is that the type of developer that takes an interest in understanding how to design good software and takes the time to read forums like this can probably be trusted to build a really sound and reliable threaded application.
I would like someone to consider another planet of development though, where arbitary timelines are based on the complexity of the business problem, which of course is not the same as the complexity of the implementation that developers face (if this makes any sense). The only thing that matters is making the deadline and anything that cannot be detected as an error is most certainly not even a consideration.
My preference in some organisations would be to keep the crackers in the box and use more appropriate solutions to simple problems, rather than allowing unnecessary complex solutions to be tampered with by any unsuspecting team member.
I'll close this message, unless there are any other comments.
|
|
|
|
|
Threading techniques have a purpose; here are the two main reasons AFAIK.
1. Organizational asset.
Threads can be used to keep things clearly separated, by hiding them inside some classes, and making sure the threads, their locks and their shared data is not publicly accessible. Imagine an app needing to communicate with two serial ports; you either have to poll a lot, which is wasteful, or you assign a thread to each serial input, which can be neat and simple.
2. Performance asset.
Threads can be used to improve performance: any time your CPU is not running at 100% chances are your code is waiting on something instead of working on some other part of the same job, and that is where threading can help.
You may feel reluctant to use threads as you aren't sufficiently familiar with them; the same could apply to files, to databases, to regexes. You need to know them to use them properly. Files may seem easy, databases may be more difficult to get good performance, threads may frighten you. It all depends on your needs and your skills. And everything can be abused when you don't really understand the basics. Bugs are always possible, discipline, creating small entities, and performing tests (unit and other) should overcome most of the problems.
Luc Pattyn
Have a look at my entry for the lean-and-mean competition; please provide comments, feedback, discussion, and don’t forget to vote for it! Thank you.
Local announcement (Antwerp region): Lange Wapper? Neen!
|
|
|
|
|
The main problem with threads, judging by some of the questions/comments I have seen here on the CP forums, is that people use them without fully understanding their primary purpose (as so clearly described by Luc above). Like any tool they can solve some problems, but in the wrong hands, or used the wrong way, they can wreak havoc.
|
|
|
|
|
Threading in general doesn't faze me, provided that it is clear which aspects of libraries are thread-safe and which are not. The biggest key is to make sure that there are clear boundaries of interaction between threads. For example, a particular thread whose job is solely to receive commands from a TCP port and place them into a queue structure. The queue structure is thread-safe, and the application code is prepared to deal with data from different TCP ports arriving interleaved, so I don't worry about detailed interaction between threads.
What has made me paranoid is reading about how IA64, unlike other systems, does not guarantee cache coherency between processors in the absence of explicit interlocks. Unless programs default to only running on a single processor, that seems like a sure-fire recipe for random non-reproduceable and non-trackable bugs unless someone can come up with a way to ensure that code which doesn't use proper interlocks on memory accesses would be very likely to fail (e.g. by rigging things so a non-interlocked write by one processor will have a 50% chance of showing up in a non-interlocked read by another, rather than having in some cases a 99.99% chance).
I suppose in one sense an architecture isn't "broken" if it conforms to specifications. On the other hand, I would consider a specification broken that would allow the following 'thread2_test' to yield a value of 0x12340000.
volatile int val1, val2;
void set_val1(void)
{
val1 = 0x5678;
}
void thread1_main(void)
{
set_val1();
val2 = 0x1234;
}
int thread2_main(void)
{
int read1,read2;
read1 = val1;
read2 = val2;
return read1 + 65536*read2;
}
From my perspective, it should not be unreasonable for a programmer to expect that all side-effects from a function call will have completed before any statements following the function call are executed; even if a function is inlined, a compiler should still enforce that. By my understanding, however, when running .net on IA64 such behavior is not guaranteed. If thread1_main and thread2_main are scheduled to start simultaneously, there is no guarantee that thread2 won't see val2 get written before it sees val1 get written. How can one realistically write bulletproof code on such a system?
|
|
|
|
|
supercat9 wrote: By my understanding, however, when running .net on IA64 such behavior is not guaranteed
I'm not exactly sure, but, the CLR specs seem to guarantee more than IA64 - doesn't mean that it would just have to Make It So regardless of the underlying architecture?
|
|
|
|
|
I think in 15 years or so; threads will be seen as arcane programming technique; just like programming in assembler is nowadays.
Just like the .NET runtime solved the problems of "unexplained crashes" caused by pointer misuse in C / C++; there will be solutions to the problems caused by threads.
Research in this area has only recently with the start of the multi-core era gotten up to speed.
No one nowadays is building large applications using assembly language. It has been replaced with more high-level languages: structured programming instead of go-to, etc.
Exactly the same will happen with threads.
There are a couple alternatives on the horizon:
- structured concurrency (e.g. Parallel Framework in .NET 4.0) - yes, this isn't a fundamental change; but then again, "if () {} else {}" wasn't really a fundamental step over "JNZ elseLabel".
- languages managing concurrency (e.g. Erlang)
- transactional memory
|
|
|
|
|
Hi all,
I have a .NET(C#) DLL which I have to use from Visual Basic 6.0 application. I am using regasm tool to make tlb file and register the dll. Then I can use the tlb file from VB6.
Now I have to make an installer. I have heard that its possible from installer project to make tlb without using regasm tool, but did not get any sample yet.
Is it really possible to register .NET DLL without using regasm? If possible it would be great because I do not need to add any .NET framework in my installer.
If this is possible can anyone please give me a complete sample of this?
Please response.
|
|
|
|
|
hasan0305069 wrote: If possible it would be great because I do not need to add any .NET framework in my installer.
True, you don't have to add the .NET Framework to the installer, but the machine your .DLL is installed on MUST have the .NET Framework installed in order to use your .DLL.
|
|
|
|
|
I have a program. I really don't want it to be passed around. Is it possible to make my program run on only one computer? I could probably use the computer name but that can be changed. Is there a different way?
|
|
|
|
|
|
He was out when I called.
|
|
|
|
|
No, there isn't. THat's been the Holy Grail of Copy Protection since the dawn of time and noone has come up with a foolproof solution.
|
|
|
|
|
About the closest you could get would be to use the MAC Address. Not perfect since the network card could be changed but at least it would be more difficult than changing the computer name.
only two letters away from being an asset
|
|
|
|
|
If this is in the wrong forum, feel free to move it. I was not sure where I would get the most help.
I have a Solution that has several 'plugin' files that need to be packaged along with the main Solution for deployment. The steps I take are:
-Publish via Visual Studio 2008 (so it creates the index.htm and setup.exe files)
-Drop the additional files into the publish folder on the web server
-Open the .manifest file with MageUI, add the new files, re-sign with the key provided by VS2008
-Open each of the .application files with MageUI, select the modified .manifest file, re-sign
When I click the install button I get all the way through to just after the install completes, then get a "Application cannot be started." dialog. The log is below.
This is in Windows XP SP2, the Solution is .Net 2.0 and is being compiled in Visual Studio 2008.
What am I doing wrong?
PLATFORM VERSION INFO
Windows : 5.1.2600.196608 (Win32NT)
Common Language Runtime : 2.0.50727.3082
System.Deployment.dll : 2.0.50727.3053 (netfxsp.050727-3000)
mscorwks.dll : 2.0.50727.3082 (QFE.050727-3000)
dfdll.dll : 2.0.50727.3053 (netfxsp.050727-3000)
dfshim.dll : 2.0.50727.3053 (netfxsp.050727-3000)
SOURCES
Deployment url : http:
Server : Microsoft-IIS/7.0
X-Powered-By : ASP.NET
Deployment Provider url : http:
Application url : http:
Server : Microsoft-IIS/7.0
X-Powered-By : ASP.NET
IDENTITIES
Deployment Identity : Deerfield.Client.application, Version=1.0.0.7, Culture=en-US, PublicKeyToken=4bdb671eb25a08c3, processorArchitecture=msil
Application Identity : Deerfield.Client.exe, Version=1.0.0.7, Culture=en-US, PublicKeyToken=4bdb671eb25a08c3, processorArchitecture=msil, type=win32
APPLICATION SUMMARY
* Installable application.
ERROR SUMMARY
Below is a summary of the errors, details of these errors are listed later in the log.
* Activation of http:
+ A device attached to the system is not functioning. (Exception from HRESULT: 0x8007001F)
COMPONENT STORE TRANSACTION FAILURE SUMMARY
* Transaction at [9/9/2009 9:09:50 AM]
- Staging of a component (WeCare.Billing.dcm.genman) did not succeed.
- Staging of a component file (WeCare.Billing.dcm) did not succeed.
- Staging of a component (Ionic.Utils.Zip.dll.genman) did not succeed.
- Staging of a component file (Ionic.Utils.Zip.dll) did not succeed.
- Staging of a component (Deerfield.Base.dll.genman) did not succeed.
- Staging of a component file (Deerfield.Base.dll) did not succeed.
- Staging of a component (CrystalHelper.dll.genman) did not succeed.
- Staging of a component file (CrystalHelper.dll) did not succeed.
- Staging of a component (WebCrawler.dll.genman) did not succeed.
- Staging of a component file (WebCrawler.dll) did not succeed.
- Staging of a component (Deerfield.Client.exe.genman) did not succeed.
- Staging of a component file (Deerfield.Client.exe) did not succeed.
- Staging of a component (CTE.Plugins.dcm.genman) did not succeed.
- Staging of a component file (CTE.Plugins.dcm) did not succeed.
- Staging of a component (Deerfield.Plugins.Base.dll.genman) did not succeed.
- Staging of a component file (Deerfield.Plugins.Base.dll) did not succeed.
- Installation of deployment (http:
- Setting one or more of the deployment metadata did not succeed.
WARNINGS
There were no warnings during this operation.
OPERATION PROGRESS STATUS
* [9/9/2009 9:09:43 AM] : Activation of http:
* [9/9/2009 9:09:43 AM] : Processing of deployment manifest has successfully completed.
* [9/9/2009 9:09:43 AM] : Installation of the application has started.
* [9/9/2009 9:09:43 AM] : Processing of application manifest has successfully completed.
* [9/9/2009 9:09:46 AM] : Request of trust and detection of platform is complete.
* [9/9/2009 9:09:49 AM] : Downloading of subscription dependencies is complete.
* [9/9/2009 9:09:49 AM] : Commit of the downloaded application has started.
ERROR DETAILS
Following errors were detected during this operation.
* [9/9/2009 9:09:50 AM] System.Runtime.InteropServices.COMException
- A device attached to the system is not functioning. (Exception from HRESULT: 0x8007001F)
- Source: System.Deployment
- Stack trace:
at System.Deployment.Internal.Isolation.IStore.Transact(IntPtr cOperation, StoreTransactionOperation[] rgOperations, UInt32[] rgDispositions, Int32[] rgResults)
at System.Deployment.Internal.Isolation.Store.Transact(StoreTransactionOperation[] operations, UInt32[] rgDispositions, Int32[] rgResults)
at System.Deployment.Application.ComponentStore.SubmitStoreTransaction(StoreTransactionContext storeTxn, SubscriptionState subState)
at System.Deployment.Application.ComponentStore.SubmitStoreTransactionCheckQuota(StoreTransactionContext storeTxn, SubscriptionState subState)
at System.Deployment.Application.ComponentStore.CommitApplication(SubscriptionState subState, CommitApplicationParams commitParams)
at System.Deployment.Application.SubscriptionStore.CommitApplication(SubscriptionState& subState, CommitApplicationParams commitParams)
at System.Deployment.Application.ApplicationActivator.InstallApplication(SubscriptionState& subState, ActivationDescription actDesc)
at System.Deployment.Application.ApplicationActivator.PerformDeploymentActivation(Uri activationUri, Boolean isShortcut, String textualSubId, String deploymentProviderUrlFromExtension, BrowserSettings browserSettings, String& errorPageUrl)
at System.Deployment.Application.ApplicationActivator.ActivateDeploymentWorker(Object state)
COMPONENT STORE TRANSACTION DETAILS
* Transaction at [9/9/2009 9:09:50 AM]
+ System.Deployment.Internal.Isolation.StoreOperationStageComponent
- Status: Installed
- HRESULT: 0x0
- Manifest: B0T18YCN.VEK.application
+ System.Deployment.Internal.Isolation.StoreOperationSetDeploymentMetadata
- Status: Set
- HRESULT: 0x0
+ System.Deployment.Internal.Isolation.StoreOperationStageComponent
- Status: Installed
- HRESULT: 0x0
- Manifest: Deerfield.Client.exe.manifest
+ System.Deployment.Internal.Isolation.StoreOperationStageComponentFile
- Status: Installed
- HRESULT: 0x0
- File: Modules\CTE.Plugins.exe.config
+ System.Deployment.Internal.Isolation.StoreOperationStageComponentFile
- Status: Installed
- HRESULT: 0x0
- File: Modules\CTE.Plugins.pdb
+ System.Deployment.Internal.Isolation.StoreOperationStageComponentFile
- Status: Installed
- HRESULT: 0x0
- File: Modules\WeCare.Billing.pdb
+ System.Deployment.Internal.Isolation.StoreOperationStageComponentFile
- Status: Installed
- HRESULT: 0x0
- File: Resources\Arrow_Right.png
+ System.Deployment.Internal.Isolation.StoreOperationStageComponentFile
- Status: Installed
- HRESULT: 0x0
- File: Resources\Arrow_Left.png
+ System.Deployment.Internal.Isolation.StoreOperationStageComponentFile
- Status: Installed
- HRESULT: 0x0
- File: Deerfield.Base.pdb
+ System.Deployment.Internal.Isolation.StoreOperationStageComponentFile
- Status: Installed
- HRESULT: 0x0
- File: Modules\Deerfield.Plugins.Base.pdb
+ System.Deployment.Internal.Isolation.StoreOperationStageComponentFile
- Status: Installed
- HRESULT: 0x0
- File: Deerfield.Client.pdb
+ System.Deployment.Internal.Isolation.StoreOperationStageComponentFile
- Status: Installed
- HRESULT: 0x0
- File: Resources\Icon_Normal.ico
+ System.Deployment.Internal.Isolation.StoreOperationStageComponentFile
- Status: Installed
- HRESULT: 0x0
- File: Modules\WeCare.Billing.exe.config
+ System.Deployment.Internal.Isolation.StoreOperationStageComponentFile
- Status: Installed
- HRESULT: 0x0
- File: Deerfield.Client.exe.config
+ System.Deployment.Internal.Isolation.StoreOperationStageComponent
- Status: Failed
- HRESULT: 0x8007001f
- Manifest: WeCare.Billing.dcm.genman
+ System.Deployment.Internal.Isolation.StoreOperationStageComponentFile
- Status: Failed
- HRESULT: 0x1
- File: WeCare.Billing.dcm
+ System.Deployment.Internal.Isolation.StoreOperationStageComponent
- Status: Failed
- HRESULT: 0x1
- Manifest: Ionic.Utils.Zip.dll.genman
+ System.Deployment.Internal.Isolation.StoreOperationStageComponentFile
- Status: Failed
- HRESULT: 0x1
- File: Ionic.Utils.Zip.dll
+ System.Deployment.Internal.Isolation.StoreOperationStageComponent
- Status: Failed
- HRESULT: 0x1
- Manifest: Deerfield.Base.dll.genman
+ System.Deployment.Internal.Isolation.StoreOperationStageComponentFile
- Status: Failed
- HRESULT: 0x1
- File: Deerfield.Base.dll
+ System.Deployment.Internal.Isolation.StoreOperationStageComponent
- Status: Failed
- HRESULT: 0x1
- Manifest: CrystalHelper.dll.genman
+ System.Deployment.Internal.Isolation.StoreOperationStageComponentFile
- Status: Failed
- HRESULT: 0x1
- File: CrystalHelper.dll
+ System.Deployment.Internal.Isolation.StoreOperationStageComponent
- Status: Failed
- HRESULT: 0x1
- Manifest: WebCrawler.dll.genman
+ System.Deployment.Internal.Isolation.StoreOperationStageComponentFile
- Status: Failed
- HRESULT: 0x1
- File: WebCrawler.dll
+ System.Deployment.Internal.Isolation.StoreOperationStageComponent
- Status: Failed
- HRESULT: 0x1
- Manifest: Deerfield.Client.exe.genman
+ System.Deployment.Internal.Isolation.StoreOperationStageComponentFile
- Status: Failed
- HRESULT: 0x1
- File: Deerfield.Client.exe
+ System.Deployment.Internal.Isolation.StoreOperationStageComponent
- Status: Failed
- HRESULT: 0x1
- Manifest: CTE.Plugins.dcm.genman
+ System.Deployment.Internal.Isolation.StoreOperationStageComponentFile
- Status: Failed
- HRESULT: 0x1
- File: CTE.Plugins.dcm
+ System.Deployment.Internal.Isolation.StoreOperationStageComponent
- Status: Failed
- HRESULT: 0x1
- Manifest: Deerfield.Plugins.Base.dll.genman
+ System.Deployment.Internal.Isolation.StoreOperationStageComponentFile
- Status: Failed
- HRESULT: 0x1
- File: Deerfield.Plugins.Base.dll
+ System.Deployment.Internal.Isolation.StoreOperationInstallDeployment
- Status: Failed
- HRESULT: 0x1
- AppId: http:
+ System.Deployment.Internal.Isolation.StoreOperationSetDeploymentMetadata
- Status: Failed
- HRESULT: 0x1
+ System.Deployment.Internal.Isolation.StoreTransactionOperationType (27)
- HRESULT: 0x1
|
|
|
|
|
hi am new to linq i want to be able to insert manny rows transactiondetail with this code
ctx.MasterTransaction.InsertOnSubmit(tranmaster)
ctx.Submitchange()
For Each td As TransactionDetail In transdetail
td.TransId = tranmaster.TransId
Next
ctx.TransactionDetails.InsertAllOnSubmit (transdetail)
ctx.SubmitChanges()
i get this error 'Cannot add an entity with a key that is already in use' on submit changes
|
|
|
|
|
hi am new to ling i want to be able to insert manny rows transactiondetail with this code
ctx.MasterTransaction.InsertOnSubmit(tranmaster)
ctx.Submitchange()
For Each td As TransactionDetail In transdetail
td.TransId = tranmaster.TransId
Next
ctx.TransactionDetails.InsertAllOnSubmit (transdetail)
ctx.SubmitChanges()
i get this error 'Cannot add an entity with a key that is already in use' on submit changes
|
|
|
|
|